gpt4 book ai didi

c# - 对于 expr == null 和 expr != null,与 null 的比较结果为真

转载 作者:可可西里 更新时间:2023-11-01 09:13:33 25 4
gpt4 key购买 nike

我看到了一些非常奇怪的东西,我无法解释。我在猜测一些我不熟悉的 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;
}

有趣的是,当将表达式转换为 object 时,比较会被正确计算:

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, EquatableIdentifiableObject other)
{
if (ReferenceEquals(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; }

//...
}

这是怎么回事?

最佳答案

  • 正如您已经阐明的那样,== 运算符对您的类型失败,因为您的重载不正确。
  • 当转换为对象时,== 运算符可以正常工作,因为它是 object 的 实现的 == 被使用,而不是 EquatableIdentifiableObject 的
  • 在方法 GetObject 中,运算符计算正确,因为它不是正在使用的 ==EquatableIdentifiableObject 的 实现。在 C# 中,泛型是在运行时解析的(至少在此处相关的意义上),而不是在编译时解析。请注意,== 是静态的而不是虚拟的。所以类型 T 在运行时解析,但对 == 的调用必须在编译时解析。在编译器解析 == 时,它不会知道使用 EquatableIdentifiableObject 的 实现 ==。由于类型 T 具有此约束:where T : DBObject, new(),将使用 DBObject 的 实现(如果有)。如果 DBObject 没有定义 ==,那么将使用第一个定义的基类(直到 object)的实现。<

关于 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。如果 == 是一个实例方法,那就没问题了。由于它是一个静态方法,名称 self 有点误导。更好的名称是 o1o2 或类似这条线的名称,这样两个操作数就可以得到更平等的对待。

关于c# - 对于 expr == null 和 expr != null,与 null 的比较结果为真,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37562816/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com