代码之家  ›  专栏  ›  技术社区  ›  Fredrik Mörk

重写==并让实例比较等于空是一件坏事吗?

  •  1
  • Fredrik Mörk  · 技术社区  · 15 年前

    背景
    假设我有以下课程:

    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";
    

    …问题是:
    超载的想法==(和!=)运算符要有一个对象实例,其中 价值 null 比较等于 无效的 (部分是因为我们觉得它有意义,部分是因为对象模型中的向后兼容性问题):

    MyValue<string> a = new MyValue<string>();
    MyValue<string> b = null;
    bool areTheyEqual = (a == b); // this will be true
    

    当然,这看起来有点令人困惑,但考虑到这一点 MyClass 仅仅是一个包装器,在大多数代码中,它是相当不可见的,对您来说也是有意义的,还是因为我们忽视的原因,我们会后悔的真的很糟糕?

    3 回复  |  直到 15 年前
        1
  •  10
  •   Mehrdad Afshari    15 年前

    在我看来, == C中的运算符已经足够令人困惑了。如果你这样超载,你将增加困惑的可能性。

    Class c = somethingEqualsToNullButNotNull;
    if (c == null) { // true
    }
    
    object co = c;
    if (co == null) { // false. WTF!?
    }
    
        2
  •  6
  •   Jon Skeet    15 年前

    你说你已经重写了 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 是一个 因此,您可以有一个违反合同的非空引用。

        3
  •  0
  •   cjk    15 年前

    如果重写==,那么通常最好重写.equals以使用相同的逻辑。