背景
假设我有以下课程:
public class MyValue<T>
{
public T Value { get; set; }
public static bool operator ==(MyValue<T> first, MyValue<T> second)
{
// if first and second are the same instance, they are equal
if (object.Equals(first, second))
{
return true;
}
// for each of the objects, get a value indicating whether either
// the object or its Value property is null
bool firstIsNull = object.Equals(first, null) ? true : first.Value == null;
bool secondIsNull = object.Equals(second, null) ? true : second.Value == null;
// if both are null, they are equal
if (firstIsNull && secondIsNull)
{
return true;
}
// Not both are null. If one is, they are not equal
if (firstIsNull || secondIsNull)
{
return false;
}
// Neither first nor second is null; compare their values
return first.Value.Equals(second.Value);
}
// more code implementing !=, Equals, GetHashCode, implicit conversions and so on
}
此类将用作对象模型中属性的类型。对象可能如下所示:
public class SomeClass
{
public SomeClass()
{
SomeValue = new MyValue<string>();
}
public MyValue<string> SomeValue { get; set; }
}
这个想法是该类只是表示其Value
属性的值。它有一些被剥离的功能,因为它与问题无关(一些验证和东西)。由于该类本身没有任何价值,因此我们希望它在使用时尽可能少地侵入。隐式转换允许这样的代码:
SomeClass instance = new SomeClass();
instance.SomeValue = "my string";
......问题:
重载==(和!=)运算符的想法是让Value
为null
的对象的实例与null
进行比较(部分原因是我们认为它有意义) ,部分原因是对象模型中的向后兼容性问题):
MyValue<string> a = new MyValue<string>();
MyValue<string> b = null;
bool areTheyEqual = (a == b); // this will be true
这当然看起来有点令人困惑,但鉴于MyClass
只是一个包装器,在大多数代码中它将是相当不可见的,它对你来说是否有意义,或者它是否真的很糟糕我们会因为我们忽略的原因而后悔吗?
答案 0 :(得分:10)
在我看来,C#中的==
运算符已经足够令人困惑。如果你这样超载,你就会增加混淆的可能性。
Class c = somethingEqualsToNullButNotNull;
if (c == null) { // true
}
object co = c;
if (co == null) { // false. WTF!?
}
答案 1 :(得分:6)
您说您已经覆盖Equals
以提供相同的行为。这意味着您已经违反了Equals
的合同,明确声明:
- x.Equals(a null reference (Nothing in Visual Basic)) returns false.
基本上:不,不要这样做。这会让班上的用户感到困惑。
现在Nullable<T>
出现以破坏此规则:
int? x = new int?(); // Or int? x = null;
object o = null;
Console.WriteLine(x.Equals(o)); // True
...但在这种情况下,x
不是引用,它是合同说明的一部分。使x
成为引用的唯一方法是将值设置为空,此时x
为空。在您的情况下,MyValue
是类,因此您可以拥有违反合同的非空引用。
答案 2 :(得分:0)
如果覆盖==,那么通常最好覆盖.Equals以使用相同的逻辑。