C# 重载运算符==与等于()
我正在从事一个C#项目,到目前为止,我一直在使用不可变的对象和工厂来确保类型为C# 重载运算符==与等于(),c#,operator-overloading,equals,C#,Operator Overloading,Equals,我正在从事一个C#项目,到目前为止,我一直在使用不可变的对象和工厂来确保类型为Foo的对象始终可以与=进行相等的比较 Foo对象一旦创建就不能更改,工厂总是为给定的参数集返回相同的对象。这非常有效,在整个代码库中,我们假设==总是用于检查相等性 现在,我需要添加一些功能,引入一个边缘情况,这并不总是有效的。最简单的方法是为该类型重载操作符==,这样项目中的其他代码就不需要更改了。但这给我的印象是一种代码味道:重载操作符==和不等于似乎很奇怪,我习惯了=检查引用相等,而等于检查对象相等(或任何术语
Foo
的对象始终可以与=
进行相等的比较
Foo
对象一旦创建就不能更改,工厂总是为给定的参数集返回相同的对象。这非常有效,在整个代码库中,我们假设==
总是用于检查相等性
现在,我需要添加一些功能,引入一个边缘情况,这并不总是有效的。最简单的方法是为该类型重载操作符==
,这样项目中的其他代码就不需要更改了。但这给我的印象是一种代码味道:重载操作符==
和不等于似乎很奇怪,我习惯了=
检查引用相等,而等于检查对象相等(或任何术语)
这是一个合理的担忧,还是我应该继续并重载操作符==
?我相信标准是,对于大多数类型,.Equals检查对象相似性,操作符=
检查引用相等性
我相信最佳实践是,对于不可变类型,操作符=
应该检查相似性,以及.Equals
。如果您想知道它们是否真的是同一个对象,请使用.ReferenceEquals
。请参见C#字符串
类以获取此示例。对于不可变类型,我认为重载=
以支持值相等没有任何问题。但是,我不认为我会重写==
而不重写Equals
来获得相同的语义。如果您确实重写了==
,并且出于某种原因需要检查引用相等性,则可以使用对象.ReferenceEquals(a,b)
看看这个,它确实有味道。重载==
时,应确保Equals()
和GetHashCode()
也一致。看
这看起来还可以的唯一原因是您将您的类型描述为不可变的 重载=
和覆盖之间有很大区别
当你有了这个表情
if (x == y) {
用于比较变量x和y的方法在编译时确定。这是运算符重载。声明x和y时使用的类型用于定义用于比较它们的方法。x和y中的实际类型(即子类或接口实现)是无关的。请考虑以下内容:
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to FALSE
以及以下
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // also evaluates to TRUE
这表明用于声明变量x和y的类型用于确定用于计算==的方法
通过比较,Equals是在运行时根据变量x中的实际类型确定的。Equals是对象上的一个虚拟方法,其他类型可以并确实重写它。因此,以下两个示例的计算结果均为真
object x = "hello";
object y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // evaluates to TRUE
以及以下
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x == y) { // evaluates to TRUE
string x = "hello";
string y = 'h' + "ello"; // ensure it's a different reference
if (x.Equals(y)) { // also evaluates to TRUE
根据微软自己的最佳实践,Equals方法和Equals(=)重载的结果应该是相同的
示例显示了如何根据(下文)实现此功能。注意,当重写等于时,还需要重写GetHashCode()。希望这对大家有帮助
public class Person
{
public Guid Id { get; private set; }
public Person(Guid id)
{
Id = id;
}
public Person()
{
Id = System.Guid.NewGuid();
}
public static bool operator ==(Person p1, Person p2)
{
bool rc;
if (System.Object.ReferenceEquals(p1, p2))
{
rc = true;
}
else if (((object)p1 == null) || ((object)p2 == null))
{
rc = false;
}
else
{
rc = (p1.Id.CompareTo(p2.Id) == 0);
}
return rc;
}
public static bool operator !=(Person p1, Person p2)
{
return !(p1 == p2);
}
public override bool Equals(object obj)
{
bool rc = false;
if (obj is Person)
{
Person p2 = obj as Person;
rc = (this == p2);
}
return rc;
}
public override int GetHashCode()
{
return Id.GetHashCode();
}
}
否。引用类型的“标准”是两个Equals en==返回与referenceequals相同的值。不鼓励对非不可变类型重载。此外,请注意此处的null。x、 如果x为null,则等于(null)将抛出一个NRE,而null==x将起作用。“标准”是解决某些类型问题的常用方法,如果“标准”遇到阻碍,则它不是很好的标准。比尔,但它是一个很好的标准。您想要一种a!=b
但是收集类认为它们是重复的吗?@Bill,我只是因为没有遵循标准而被咬了一口。这就是为什么我要问这里是什么。这应该足以表明标准的重要性。编码风格标准(用于提高组内的可读性)和实用编码标准(可避免很多麻烦)之间存在差异。这是非常重要的一点,我后来在测试时遇到了这一点。因为我需要operator==
来依赖于运行时类型,所以我在基类中定义了一个名为Equals()
的操作符重载。工作得很有魅力。(然后我重新定义了对象模型,把整个东西都撕掉了。但那是另一回事。)我完全不同意。使用==
是一种常见的习惯用法。仅仅因为C#将所有实体都基于对象
,并不意味着我们应该放弃这个习惯用法以防止出现本文中的情况。相反,当需要在层次结构顶部进行比较时,最好使用.Equals()
。简言之,重载==设置要调用的方法(Object.Equals或Object.ReferenceEqual)。重载对象。等于检查实际值是否相等。我说得对吗?@Xaade,对'
和Equals
有不同的行为在我看来是非常危险的。它们应该被编程来做同样的事情,你可以提供IEqualityComparer
的各种实现来提供替代的平等实现。哇,这是.NET设计中一个可怕的错误。仅仅因为我使用对象x而不是字符串x来定义变量,两个字符串就不相等的想法是一种有奖代码味道。谢谢你解释得这么好。我正在比较一个属性和一个methodinfo。这些在语义上是不可变的。顺便说一句,vb.net禁止对不提供显式重载的类型使用其=
和
相等运算符;要检查引用是否相等,请选择一个