字符串==重载运算符实际用于某些通用比较方法中

本文关键字:比较 方法 用于 运算符 重载 字符串 | 更新日期: 2023-09-27 18:24:36

我目前正在阅读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

有人能澄清这种行为的原因是什么吗?示例一和示例三之间真的有这么大的区别吗?

字符串==重载运算符实际用于某些通用比较方法中

是的,有很大的不同。

在示例1中,intro1intro2指代不同的对象。在示例中2和3,intro1intro2具有相同的值-它们引用相同的对象,因此如果调用Object.ReferenceEquals(intro1, intro2),则返回true。

这种行为的原因是编译器必须在编译时计算出==AreReferencesEqual中的含义,而不知道T的值。它无法判断您将使用类型参数string来调用它,因此它不知道==的过载。这基本上与您不能在AreReferencesEqual中调用任何其他字符串特定成员的原因相同。

C#中的字符串文字是内部的,也就是说,所有使用相等字符串文字的情况都会导致在整个应用程序中引用该字符串的单个字符串实例。正如Jon所说,您的通用方法确实使用了==运算符的object重载,但尽管您使用的是object重载,您还是为两个参数传递了相同的引用。在Jon最初的例子中,他竭尽全力防止字符串被插入(通过在运行时计算它们),从而确保他有两个不同的字符串实例,带有单独的引用,恰好代表相同的字符序列。