IEnumerable<T>:可以使用 Equals 方法但不能使用相等运算符
IEnumerable<T>: Can use Equals method but not equality operator
public static IEnumerable<T> Method<T>(IEnumerable<T> iterable){
T previous = default(T);
foreach(T current in iterable){
if (!current.Equals(previous)){
previous = current;
yield return current;
}
}
}
我对这段代码没有任何疑问,但为什么可以使用以下方法比较两个类型 T 的对象:
if (!current.Equals(previous))
那为什么不能比较使用:
if (!current == previous)
!给你一个错误说
Operator '!' cannot be applied to operand of type 'T'
如果你删除它,你会得到:
Operator '==' cannot be applied to operands of type 'T' and 'T'
我放弃了一个代码挑战,因为它似乎在告诉我你真的无法将一个 T 与另一个进行比较。然后我发现你可以做到这一点,但只需使用不同的 syntax/using 特定方法。
谁能告诉我为什么会这样?
.Equals
是 System.Object
的一部分。现在没有办法限制泛型支持特定的运算符重载。但是,您可以使用 IEquatable<T>
或 IEqualityComparer<T>
来确保类型实现其相等性定义。
请参阅语言规范的 this section,其中指定了 ==
。您可以看到该语言仅预定义了 ==
这些重载:
bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);
bool operator ==(float x, float y);
bool operator ==(double x, double y);
bool operator ==(decimal x, decimal y);
bool operator ==(bool x, bool y);
bool operator ==(E x, E y); // for every enum E
bool operator ==(C x, C y); // for every class C
bool operator ==(string x, string y);
bool operator ==(System.Delegate x, System.Delegate y);
你的方法中的类型参数 T
没有任何限制,那么如果它是一个结构类型呢?从上面的列表中可以看出,没有为任意结构类型定义 ==
运算符。
如果添加 T: class
约束,则可以对其使用 ==
,因为所有 类 都有一个 ==
运算符。
另一方面,在 System.Object
中声明了一个 Equals
方法,C# 中的每个类型都继承自该方法。因此,即使 T
可以是任何类型,也可以对 T
类型的值使用 Equals
。
请注意,如果对象是原始值类型、字符串或定义了 operator ==
的用户结构,则 ==
只能表示值相等。
在所有其他情况下,==
未定义(值类型)或引用 object.ReferenceEquals()
检查两个变量是否引用内存中的同一对象。
请注意,新的 record
类型支持具有值语义的 ==
运算符,即使它们是引用类型。这是因为他们在幕后实施 IEquatable<T>
并定义 operator ==
以使用 .Equals()
.
public static IEnumerable<T> Method<T>(IEnumerable<T> iterable){
T previous = default(T);
foreach(T current in iterable){
if (!current.Equals(previous)){
previous = current;
yield return current;
}
}
}
我对这段代码没有任何疑问,但为什么可以使用以下方法比较两个类型 T 的对象:
if (!current.Equals(previous))
那为什么不能比较使用:
if (!current == previous)
!给你一个错误说
Operator '!' cannot be applied to operand of type 'T'
如果你删除它,你会得到:
Operator '==' cannot be applied to operands of type 'T' and 'T'
我放弃了一个代码挑战,因为它似乎在告诉我你真的无法将一个 T 与另一个进行比较。然后我发现你可以做到这一点,但只需使用不同的 syntax/using 特定方法。
谁能告诉我为什么会这样?
.Equals
是 System.Object
的一部分。现在没有办法限制泛型支持特定的运算符重载。但是,您可以使用 IEquatable<T>
或 IEqualityComparer<T>
来确保类型实现其相等性定义。
请参阅语言规范的 this section,其中指定了 ==
。您可以看到该语言仅预定义了 ==
这些重载:
bool operator ==(int x, int y);
bool operator ==(uint x, uint y);
bool operator ==(long x, long y);
bool operator ==(ulong x, ulong y);
bool operator ==(float x, float y);
bool operator ==(double x, double y);
bool operator ==(decimal x, decimal y);
bool operator ==(bool x, bool y);
bool operator ==(E x, E y); // for every enum E
bool operator ==(C x, C y); // for every class C
bool operator ==(string x, string y);
bool operator ==(System.Delegate x, System.Delegate y);
你的方法中的类型参数 T
没有任何限制,那么如果它是一个结构类型呢?从上面的列表中可以看出,没有为任意结构类型定义 ==
运算符。
如果添加 T: class
约束,则可以对其使用 ==
,因为所有 类 都有一个 ==
运算符。
另一方面,在 System.Object
中声明了一个 Equals
方法,C# 中的每个类型都继承自该方法。因此,即使 T
可以是任何类型,也可以对 T
类型的值使用 Equals
。
请注意,如果对象是原始值类型、字符串或定义了 operator ==
的用户结构,则 ==
只能表示值相等。
在所有其他情况下,==
未定义(值类型)或引用 object.ReferenceEquals()
检查两个变量是否引用内存中的同一对象。
请注意,新的 record
类型支持具有值语义的 ==
运算符,即使它们是引用类型。这是因为他们在幕后实施 IEquatable<T>
并定义 operator ==
以使用 .Equals()
.