c# – 对于expr == null和expr!= null,与null的比较计算结果为true

前端之家收集整理的这篇文章主要介绍了c# – 对于expr == null和expr!= null,与null的比较计算结果为true前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我看到一些非常奇怪的东西,我无法解释.我猜测我不熟悉的C#的一些边缘情况,还是运行时/发射器的错误

我有以下方法

public static bool HistoryMessageExists(DBContext context,string id)
{
    return null != context.GetObject<HistoryMessage>(id);
}

在测试我的应用程序时,我看到它是不正常的 – 它为我知道的不存在于我的数据库的对象返回true.所以我停止了在方法和立即,我跑了以下:

context.GetObject<HistoryMessage>(id)
null
null == context.GetObject<HistoryMessage>(id)
true
null != context.GetObject<HistoryMessage>(id)
true

GetObject的定义如下:

public T GetObject<T>(object pk) where T : DBObject,new()
{
    T rv = Connection.Get<T>(pk);

    if (rv != null)
    {
        rv.AttachToContext(this);
        rv.IsInserted = true;
    }

    return rv;
}

有趣的是,当将表达式转换为对象时,正确评估比较:

null == (object)context.GetObject<HistoryMessage>(id)
true
null != (object)context.GetObject<HistoryMessage>(id)
false

没有平等的运算符覆盖.

编辑:事实证明有一个操作符超载,这是不正确的.但是,为什么在内部方法通用GetObject中正确评估这个方法,在这种情况下,rv的类型为HistoryMessage.

public class HistoryMessage : EquatableIdentifiableObject
{
    public static bool HistoryMessageExists(DBContext context,string id)
    {
        var rv = context.GetObject<HistoryMessage>(id);
        bool b = rv != null;
        return b;
    }

    public static void AddHistoryMessage(DBContext context,string id)
    {
        context.InsertObject(new HistoryMessage { Id = id });
    }
}

public abstract partial class EquatableIdentifiableObject : DBObject,IObservableObject
{
    public event PropertyChangedEventHandler PropertyChanged;

    [PrimaryKey]
    public string Id { get; set; }

    //...
}

public abstract partial class EquatableIdentifiableObject
{
    //...

    public static bool operator ==(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
    {
        if (ReferenceEquals(self,null))
        {
            return ReferenceEquals(other,null);
        }

        return self.Equals(other);
    }

    public static bool operator !=(EquatableIdentifiableObject self,null))
        {
            return !ReferenceEquals(other,null);
        }

        return !self.Equals(other);
    }
}

public abstract class DBObject
{
    [Ignore]
    protected DBContext Context { get; set; }

    [Ignore]
    internal bool IsInserted { get; set; }

    //...
}

这里发生了什么?

解决方法

>如你已经澄清的那样,==操作符失败,因为您的重载不正确.
>当转换为对象时,==操作符正常工作,因为它是被使用的对象的==的实现,而不是EquatableIdentifiableObject.
>在方法GetObject中,操作符正确地求值,因为它不是EquatableIdentifiableObject的正在使用的==的实现.在C#泛型中,运行时解析(至少在这里是相关的),而不是在编译时解决.注意==是静态而不是虚拟的.所以类型T在运行时被解析,但是调用==必须在编译时解决.在编译时,当编译器解析==它不会知道使用EquatableIdentifiableObject的==的实现.因为类型T有这个约束:其中T:DBObject,new(),DBObject的实现(如果有的话)将被使用.如果DBObject没有定义==,那么将使用第一个基类的实现(直到对象).

有关EquatableIdentifiableObject的实现的更多评论==:

>您可以替换此部分:

if (ReferenceEquals(self,null))
{
     return ReferenceEquals(other,null);
}

有:

// If both are null,or both are the same instance,return true.
if (object.ReferenceEquals(h1,h2))
{
    return true;
}

>更换更有力

public static bool operator !=(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
{
    ...
}

有:

public static bool operator !=(EquatableIdentifiableObject self,EquatableIdentifiableObject other)
{
    return !(self == other);
}

>为==定义签名的方法略有误导.第一个参数命名为self,第二个命名为other.如果==是一个实例方法就可以了.由于它是一种静态方法,所以名字自身有点误导.更好的名称将是o1和o2或沿着这条线的东西,以便两个操作数在更平等的基础上对待.

猜你在找的C#相关文章