StringBuilder and string equality check

I am trying this sample of code and OpTest when System.Console.WriteLine(s == t); it returns false. Can somebody explain this?

public static void OpTest<T>(T s, T t) where T : class 
{
    System.Console.WriteLine(s == t);
}
static void Main() 
{   
    string s1 = "строка";
    System.Text.StringBuilder sb = new System.Text.StringBuilder(s1);
    System.Console.Write(sb);
    string s2 = sb.ToString();
    OpTest<string>(s1, s2);
}
Jon Skeet
people
quotationmark

Your generic method will basically be performing a reference equality check - and the values of s1 and s2 refer to different but equal strings. You can show this more easily like this:

string x = "test";
string y = new string(x.ToCharArray());
Console.WriteLine(x == y); // Use string overload, checks for equality, result = true
Console.WriteLine(x.Equals(y)); // Use overridden Equals method, result = true
Console.WriteLine(ReferenceEquals(x, y)); // False because they're different objects
Console.WriteLine((object) x == (object) y); // Reference comparison again - result = false

Note that your constraint in OpTest doesn't change which == operator is used. That's determined at compile-time, based on the constraints on T. Note that operators are never overridden, only overloaded. That means the implementation is chosen at compile-time, regardless of the type at execution time.

If you constrained T to derive from some type which overloads the == operator, then the compiler will use that overload. For example:

using System;

class SillyClass
{
    public static string operator ==(SillyClass x, SillyClass y) => "equal";
    public static string operator !=(SillyClass x, SillyClass y) => "not equal";
}

class SillySubclass : SillyClass
{
    public static string operator ==(SillySubclass x, SillySubclass y) => "sillier";
    public static string operator !=(SillySubclass x, SillySubclass y) => "very silly";
}

class Test
{
    static void Main()
    {
        var x = new SillySubclass();
        var y = new SillySubclass();
        OpTest(x, y);
    }

    static void OpTest<T>(T x, T y) where T : SillyClass
    {
        Console.WriteLine(x == y);
        Console.WriteLine(x != y);
    }
}

Here the OpTest method does use the overloaded operators - but only ever the ones from SillyClass, not SillySubclass.

people

See more on this question at Stackoverflow