泛型方法中的运算符重载
此代码片段来自 C# in Depth
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
当 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));
}
上面代码片段的输出是
True
True
我无法理解为什么?
编辑:一旦您了解了字符串驻留,以下问题就不再适用。
<罢工> 第二个代码片段中的通用方法 AreReferencesEqual
是如何接收参数的?
字符串类型连接时会发生什么变化,使得==运算符不会调用String类型的重载的Equals方法?
This code snippet is from C# in Depth
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));
}
The output of the above code snippet is
True
False
When the main method is changed to
static void Main()
{
string intro1 = "My name is Jon";
string intro2 = "My name is Jon";
Console.WriteLine(intro1 == intro2);
Console.WriteLine(AreReferencesEqual(intro1, intro2));
}
The output of the above code snippet is
True
True
I cannot fathom why ?
EDIT: Once you understand string-interning following questions don't apply.
How are the parameters received at the Generic method AreReferencesEqual
in the second code snippet ?
What changes to the string type when it is concatenated to make the == operator not call the overloaded Equals method of the String type ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
对于字符串,您可能不打算使用引用相等。
要在泛型方法中访问相等和不相等,最好的选择是:
即
这仍然使用重载的
Equals
,但也处理空值等。 对于不等式,这会处理空值以及IComparable
和IComparable
。对于其他运算符,请参阅 MiscUtil。
重新回答这个问题; 在以下情况下:
您会得到
true
,true
因为编译器和运行时被设计为能够高效地处理字符串; 您使用的任何文字都会被“保留”,并且每次在您的 AppDomain 中都会使用相同的实例。 如果可能的话,编译器(而不是运行时)也会进行连接 - 即与前面的示例完全相同的代码。 完全没有区别。 但是,如果您强制它在运行时连接字符串,它会假设它们可能是短暂的,因此它们不会被保留/重用。 所以在这种情况下:
你有 4 个字符串; “Jon”(实习生)、“我的名字是”(实习生)以及“我的名字是 Jon”的两个不同实例。 因此
==
返回 true,引用相等返回 false。 但值相等 (EqualityComparer.Default
) 仍会返回 true。On the case of strings, you probably don't intend to use reference equality.
To access equality and inequality in generic methods, your best bet it:
i.e.
This still uses the overloaded
Equals
, but handles nulls etc too. For inequality, this handles nulls, and bothIComparable<T>
andIComparable
.For other operators, see MiscUtil.
Re the question; in the case of:
You get
true
,true
because the compiler and runtime is designed to be efficient with strings; any literals that you use are "interned" and the same instance is used every time in your AppDomain. The compiler (rather than runtime) also does the concat if possible - i.e.is exactly the same code as the previous example. There is no difference at all. However, if you force it to concatenate strings at runtime, it assumes they are likely to be short-lived, so they are not interned/re-used. So in the case:
you have 4 strings; "Jon" (interned), "My name is " (interned), and two different instances of "My name is Jon". Hence
==
returns true and reference equality returns false. But value-equality (EqualityComparer<T>.Default
) would still return true.今天学到了新东西。
我猜乔恩在其中一个问题中说过,我试图回答。
当您使用连接构建字符串时, == 将为 2 个匹配值的字符串返回 true,但它们不指向相同的引用(我认为这应该是由于字符串驻留所致。Jon 指出字符串驻留适用于常量或文字)。
在通用版本中,它调用 object.ReferenceEquals (这与 == 不同。对于字符串,== 进行值比较)。
因此,连接版本返回 false,而常量(文字字符串)版本返回 true。
编辑:我认为乔恩一定会以更好的方式解释这一点:)
懒惰的我,我已经买了这本书,但还没有开始看。 :(
Learnt a new thing today.
I guess Jon said in one of the questions, I tried to answer.
When you build a string using concatenation, == will return true for 2 strings of matching value but they don't point to the same reference (which I thought, it should due to string interning. Jon pointed that string interning works for constant or literals).
In the generic version, it is calling object.ReferenceEquals (which is different than ==. In case of string, == does value comparison).
As a result, the concatenated version returns false whereas the constant (literal string) version returns true.
EDIT: I think Jon must be around to explain this in a much better way :)
Lazy me, I have bought the book but have yet to get started on it. :(
它与泛型方法无关,而是与
main 的第一个版本中的字符串实例化有关:
它创建了 4 个字符串。 其中两个是编译时常量,即“Jon”和“My name is”,但是在初始化 intro1 和 intro2 时,编译器不能说 name 始终是 jon 并解析运行时的值,为每个 intro1 和 intro2 生成一个新字符串。
在第二个版本中,
你只有一个字符串,那就是一个编译时常量:“我的名字是 Jon”,你将该字符串分配给 intro1 和 intro2,这就是为什么
在第一种情况下返回 false,在第二种情况下返回 true
It has nothing to do with the generic method but the instantiation of the strings
in the first version of main you have:
which creates 4 strings. Two of which are compile time constants namely "Jon" and "My name is" however when initializing intro1 and intro2 the compiler cannot say that name is always jon and resolves the value runtime making a new string for each of intro1 and intro2.
in the second version
you only have one string and thats a compile time constant: "My name is Jon" and you assign that string to both intro1 and intro2 and that's why
returns false in the first case and true in the second