我目前正在阅读Jon Skeet的C# in Depth, 2nd Edition
。我想引用清单3.5:
static bool AreReferencesEqual<T>(T first, T second) where T : class
{
return first == second;
}
...
string name = "John";
string intro1 = "My name is " + name;
string intro2 = "My name is " + name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);
作者写道,对于第一次比较,输出应该是True
,对于第二次比较,输出应该是False
,因为在泛型方法中不使用重载的运算符。当然,他对输出是正确的。
现在让我们稍微改变一下代码片段:
static bool AreReferencesEqual<T>(T first, T second) where T : class
{
return first == second;
}
...
string intro1 = "John";
string intro2 = "John";
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);
现在两种方法都比较了返回True
。让我们再次调整代码,因为这可能与先前我们比较使用已存在的string
创建的变量这一事实有关。
static bool AreReferencesEqual<T>(T first, T second) where T : class
{
return first == second;
}
...
string name = "John"
string intro1 = name;
string intro2 = name;
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2);
两种情况下的输出均为True
。
任何人都可以澄清这种行为的原因是什么?第一个例子和第三个例子之间真的有这么大差异吗?
答案 0 :(得分:4)
是的,存在巨大差异。
在示例1中,intro1
和intro2
引用不同的对象。在例子中
2和3,intro1
和intro2
具有相同的值 - 它们引用相同的对象,因此如果您调用Object.ReferenceEquals(intro1, intro2)
将返回true。
行为的原因是编译器必须在编译时计算==
在AreReferencesEqual
中的含义,而不知道T
的值。它无法告诉您将使用类型参数string
来调用它,因此它不知道==
的重载。这基本上与您无法在AreReferencesEqual
中调用任何其他字符串特定成员的原因相同。
答案 1 :(得分:3)
C#中的字符串文字被实现,也就是说,所有使用相等字符串文字的结果都会导致单个字符串实例在整个应用程序中引用该字符串。正如Jon所说,你的通用方法确实正在使用object
运算符的==
重载,但尽管您使用了object
重载这一事实,但您还是要通过两个参数的参考相同。在Jon的原始示例中,他不遗余力地阻止字符串(通过在运行时计算它们),从而确保他有两个不同的字符串实例,具有单独的引用,恰好代表相同的序列人物。