Сравнение дженериков в C#

почему этот код печатает False?

    class Program
{
    public static void OpTest<T>(T s, T t) where T : class
    {
        Console.WriteLine(s == t);
    }

    static void Main()
    {
        string s1 = "string";
        System.Text.StringBuilder sb = new System.Text.StringBuilder(s1);
        string s2 = sb.ToString();
        OpTest(s1, s2);
    }
}

3 ответов


С документы на == оператор:

для предопределенных типов значений, оператор равенства (==) возвращает true Если значения операндов равны, false иначе. Для ссылочных типов, отличных от string, == возвращает true если два операнда указывают на один объект. Для string тип, == сравнивает значения строк.

С T не может быть гарантированно тип значения как универсальный, компилятор должен предположить, что это ссылочный тип.


Я бы и согласен с вами в комментариях, но ваш пример особенно хорош.

правильно ли я понимаю, что при сравнении они сравниваются не как строки, а как объекты, поэтому сравниваются не их значения, а адреса, на которые они указывают?

это на самом деле не так.

как говорится в == документация

для справочных типов, отличных от строке == возвращает true, если два операнда указывают на один объект. Для string тип, == сравнивает значения строк.

в вашем конкретном случае причина в том, что вы бросаете их как дженерики, прежде чем сравнивать их. Но если это были объекты string, то стоимостью будет сравнивать.


Я считаю полезным создать неродовой OpTest метод для подтверждения того, что происходит. Универсальный метод обрабатывает параметры как Object типы и не использовать == перегрузка String, что является частным случаем для сравнения значений.

в обоих случаях параметры типа String но общий метод рассматривает их "обобщенно" при проведении сравнения.

void Main()
{
    string s1 = "string";
    System.Text.StringBuilder sb = new System.Text.StringBuilder(s1);
    string s2 = sb.ToString();
    TestClass.OpTest(s1, s2);
    TestClass.OpTest<string>(s1, s2);

    // OpTest: s is System.String, t is System.String
    // True
    // OpTest<T>: s is System.String, t is System.String
    // False
}

public class TestClass
{
    public static void OpTest(string s, string t)
    {
        Console.WriteLine($"OpTest: s is {s.GetType()}, t is {t.GetType()}");
        // Uses String's == operator, which compares the values
        Console.WriteLine(s == t);
    }

    public static void OpTest<T>(T s, T t) where T : class
    {
        Console.WriteLine($"OpTest<T>: s is {s.GetType()}, t is {t.GetType()}");
        // Uses Object's == operator, which is a reference comparison
        Console.WriteLine(s == t);
    }
}