通用方法中的运算符重载

时间:2009-06-30 03:48:45

标签: c# .net 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));
    }

上面代码段的输出是

True 
False

当主要方法改为

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

上面代码段的输出是

True 
True

我无法理解为什么?

编辑:一旦你理解了字符串实习,下面的问题就不适用了。

<击> 如何在第二个代码段中的通用方法AreReferencesEqual中接收参数?

<击>

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

3 个答案:

答案 0 :(得分:13)

在字符串的情况下,您可能不打算使用引用相等性。 要获得通用方法中的平等和不平等,最好打赌:

EqualityComparer<T>.Default.Equals(x,y); // for equality
Comparer<T>.Default.Compare(x,y); // for inequality

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

这仍然使用重载的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));

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

    string intro1 = "My name is " + "Jon";
    string intro2 = "My name is " + "Jon";
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));

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

    string name = "Jon";
    string intro1 = "My name is " + name;
    string intro2 = "My name is " + name;
    Console.WriteLine(intro1 == intro2);
    Console.WriteLine(AreReferencesEqual(intro1, intro2));
你有4个字符串; “Jon”(实习),“我的名字”(实习)和两个不同的实例“我的名字是Jon”。因此==返回true,引用相等性返回false。但是价值平等(EqualityComparer<T>.Default)仍然会返回真实。

答案 1 :(得分:5)

今天学到了一件新东西。

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

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

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

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

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

答案 2 :(得分:2)

它与泛型方法无关,而是字符串的实例化

在main的第一个版本中你有:

string name = "Jon";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;

创建4个字符串。其中两个是编译时常量,即“Jon”和“My name is”但是在初始化intro1和intro2时,编译器不能说该名称总是jon并且解析值运行时为每个intro1和intro2创建一个新字符串。

在第二个版本中

string intro1 = "My name is Jon";
string intro2 = "My name is Jon";

你只有一个字符串,那是一个编译时间常量:“我的名字是Jon”,你将该字符串分配给intro1和intro2,这就是为什么

AreReferencesEqual(intro1, intro2)

在第一种情况下返回false,在第二种情况下返回true