简体   繁体   中英

Comparison of Generics in C#

Why does this code prints 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);
    }
}

Do I understand correctly that when compared, they are compared not as strings, but as objects, which is why not their values are compared, but the addresses to which they point?

From the docs for the == operator :

For predefined value types, the equality operator ( == ) returns true if the values of its operands are equal, false otherwise. For reference types other than string , == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.

Since T cannot be guaranteed to be a value type as it's generic, the compiler must assume it is a reference type.

I would normally go and agree with you in the comments, but your example is especially good.

Do I understand correctly that when compared, they are compared not as strings, but as objects, which is why not their values are compared, but the addresses to which they point?

That is actually not true.

As stated in the == documentation,

For reference types other than string, == returns true if its two operands refer to the same object. For the string type, == compares the values of the strings.

In your particular case, the reason is you're casting them as generics before comparing them. But if those were string objects, the value would be compared.

I find it helpful to create a non-generic OpTest method to confirm what's happening. The generic method treats the parameters as Object types and does not use the == overload for String , which is a special case to compare the values.

In both cases the parameters are type String but the generic method treats them "generically" when making the comparison.

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);
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM