怎么能(x.y!= null&&((object)x.y)== null)是真的吗?

时间:2016-03-25 13:43:17

标签: c#

我刚写了一段代码,其行为与我预期的完全不同。 它似乎告诉我,我不知道关于物体的一切,所以我谦卑地转向堆叠溢出的同事的智慧,指出我正确的方向。

这是困扰我的代码:

[Test]
public void TestMySanity()
{
    var oldSet = new Identifier[0];
    var newSet = new[]
    {
        new Identifier("1"),
        new Identifier("2")
    };

    var changes = uut.TrackChanges(oldSet, newSet, x => x).ToArray();

    ChangeRecord<Identifier> xx = changes.FirstOrDefault(x => x.New != null && x.Old != null);
    if (xx != null)
    {
        if (xx.Old != null && ((object) xx.Old) == null)
        {
            Console.WriteLine("How can something be not null and null at the same time?");
        }
        Assert.Fail("PS: this test expects a change record with Old = null and New = an Identifier");
    }
}

要清楚 - &gt;此代码进入Console.WriteLine(...),这不应该发生......

我试图变得更聪明的一些事情:

Console.WriteLine("Is Object? " + (xx.Old is Object)); // = false
Console.WriteLine("Reference Equals? " + Object.ReferenceEquals(xx.Old, null)); // = true

try { Console.WriteLine(xx.Old.GetType().Name); }
catch (Exception ex)
{ Console.WriteLine("GetType() -> " + ex.Message);}
//Throws: Object reference not set to an instance of an object.

关于这个问题的评论似乎表明类标识符对于这个问题很重要,所以这里是:

public class Identifier : IComparable, IComparable<Identifier>, IEquatable<Identifier>
{
    //Var
    protected readonly IComparable Key;

    //Constructor
    public Identifier(IComparable key)
    {
        Key = key;
        if (key == null) throw new ArgumentNullException("key");
    }

    //Hashcode (Must be overridden when equals is overridden.)
    public override int GetHashCode()
    {
        return Key.GetHashCode();
    }

    public override string ToString()
    {
        return "[" + Key + "]";
    }

    //Compare
    public virtual int CompareTo(object obj)
    {
        return CompareTo((Identifier)obj);
    }

    public virtual int CompareTo(Identifier other)
    {
        if (other == null) return 1;
        return Key.CompareTo(other.Key);
    }

    //Equals
    public override bool Equals(object obj)
    {
        return Equals((obj as Identifier));
    }

    public virtual bool Equals(Identifier other)
    {
        if (ReferenceEquals(null, other)) return false;
        return Key.Equals(other.Key);
    }

    //Can be done because a Identifier is immutable
    public static bool operator ==(Identifier A, Identifier B)
    {
        if (ReferenceEquals(A, null)) return false;
        return A.Equals(B);
    }

    public static bool operator !=(Identifier A, Identifier B)
    {
        return !(A == B);
    }
}

2 个答案:

答案 0 :(得分:7)

发现错误:

public static bool operator ==(Identifier A, Identifier B)
{
    if (ReferenceEquals(A, null)) return false;
    return A.Equals(B);
}

如果Bnull会怎样? A == B应该返回true,遗憾的是您的比较将return false;

将其更改为:

    if (ReferenceEquals(A, null)) return ReferenceEquals(B, null);
    return A.Equals(B);

一般来说,通过强制转换为object类似((object) xx.Old) == null,您迫使C#编译器使用object==运算符,它只执行object.ReferenceEquals(A, B),所以你绕过你的错误代码。

答案 1 :(得分:2)

使用==!= 运营商

public class MyX {
  public MyY y {
    get;
    set;
  }
}

public class MyY {
  public static Boolean operator == (MyY left, Object right) {
    return true;
  }

  public static Boolean operator != (MyY left, Object right) {
    return true;
  }
}

...

var x = new MyX();

if (x.y != null && (((Object) x.y) == null)) {
  Console.Write("You've got it");
}

所以可能