通用方法中的运算符重载

abh*_*ash 6 .net c# generics string-interning

此代码段来自深度中的C#

    static bool AreReferencesEqual<T>(T first, T second)
        where T : class
    {
        return first == second;
    }

    static void Main()
    {
        string name = "Jon";
        string intro1 = "My name is " + name;
        string intro2 = "My name is " + name;
        Console.WriteLine(intro1 == intro2);
        Console.WriteLine(AreReferencesEqual(intro1, intro2));
    }
Run Code Online (Sandbox Code Playgroud)

上面代码片段的输出是

True 
False
Run Code Online (Sandbox Code Playgroud)

当main方法改为

    static void Main()
    {
        string intro1 = "My name is Jon";
        string intro2 = "My name is Jon";
        Console.WriteLine(intro1 == intro2);
        Console.WriteLine(AreReferencesEqual(intro1, intro2));
    }
Run Code Online (Sandbox Code Playgroud)

上面代码片段的输出是

True 
True
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么?

编辑:一旦你理解字符串实习以下问题不适用.

如何AreReferencesEqual在第二个代码片段中的Generic方法中接收参数?

连接时字符串类型有什么变化,以使==运算符不调用String类型的重载Equals方法?

Mar*_*ell 13

对于字符串的情况,您可能不打算使用引用相等性.要获得通用方法中的平等和不平等,最好的办法是:

EqualityComparer<T>.Default.Equals(x,y); // for equality
Comparer<T>.Default.Compare(x,y); // for inequality
Run Code Online (Sandbox Code Playgroud)

static bool AreValuesEqual<T>(T first, T second)
    where T : class
{
    return EqualityComparer<T>.Default.Equals(first,second);
}
Run Code Online (Sandbox Code Playgroud)

这仍然使用重载Equals,但也处理空值等.对于不等式,它处理空值,以及IComparable<T>IComparable.

对于其他运营商,请参阅MiscUtil.


重新提出问题; 如果是:

    string intro1 = "My name is Jon";
    string intro2 = "My name is Jon";
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));
Run Code Online (Sandbox Code Playgroud)

你得到true,true因为编译器和运行时被设计为对字符串有效; 您使用的任何文字都是"interned",并且每次在AppDomain中都使用相同的实例.如果可能的话,编译器(而不是运行时)也会执行连接 - 即

    string intro1 = "My name is " + "Jon";
    string intro2 = "My name is " + "Jon";
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));
Run Code Online (Sandbox Code Playgroud)

完全相同的代码与前面的例子.完全没有区别.但是,如果强制它在运行时连接字符串,它会假定它们可能是短暂的,因此它们不会被实习/重用.所以在这种情况下:

    string name = "Jon";
    string intro1 = "My name is " + name;
    string intro2 = "My name is " + name;
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));
Run Code Online (Sandbox Code Playgroud)

你有4个字符串; "Jon"(实习),"我的名字是"(实习),以及"我的名字是Jon"的两个不同实例.因此==返回true,引用相等返回false.但是value-equality(EqualityComparer<T>.Default)仍然会返回true.


sha*_*esh 5

今天学到了新东西.

我想Jon在其中一个问题中说过,我试着回答.

使用连接构建字符串时,==将为2个匹配值字符串返回true,但它们不指向相同的引用(我认为,它应该由于字符串内部.Jon指出字符串实习适用于常量或文字).

在通用版本中,它调用object.ReferenceEquals(与==不同.在字符串的情况下,==进行值比较).

因此,连接版本返回false,而常量(文字字符串)版本返回true.

编辑:我认为乔恩必须以更好的方式来解释这个问题:)
懒惰我,我已经买了这本书但尚未开始使用它.:(