为什么ReferenceEquals和==运算符的行为与Equals不同

我有一个实体不会覆盖任何相等的成员\运算符。
比较它们的两个代理(我从Nhibernate session得到它们)时,结果根据相等方法改变:

  • ReferenceEquals(第一,第二) – false。
  • 第一个==第二个 – 假
  • 等于(第一,第二) – 是的。

这更加奇怪,因为它们都存在于同一个会话上下文中并且根据Nhibernate文档 :

NHibernate只保证单个ISession内的身份(a == b,Equals()的默认实现!)

和:

该实例当前与持久性上下文相关联。 它具有持久标识(主键值),也许还有数据库中的相应行。 对于特定的持久化上下文,NHibernate保证持久标识等同于CLR标识(对象的内存中位置)。

那么为什么不是所有的等式方法都返回真实呢?


更新:
我以这种方式获得了enteties,查询ChildEntity的会话并获得带有Linq select的Parents Entities,类似于:

 var childs = session.Query(); var parents = childs.Select(x => x.ParentEntity).ToList(); 

编辑

您可能正在使用结构? 见下文


我认为引用类型显示了您期望的行为:

 public class Program { class X { int x,y; } public static void Main(string[] args) { X a = new X(); X b = new X(); System.Console.WriteLine(a == b); System.Console.WriteLine(a.Equals(b)); System.Console.WriteLine(Equals(a,b)); System.Console.WriteLine(ReferenceEquals(a,b)); } } 

打印:

 False False False False 

对于结构,事情是不同的(纪念a==b测试,不编译结构:)

 public class Program { struct X { int x,y; } public static void Main(string[] args) { X a = new X(); X b = new X(); //System.Console.WriteLine(a == b); System.Console.WriteLine(a.Equals(b)); System.Console.WriteLine(Equals(a,b)); System.Console.WriteLine(ReferenceEquals(a,b)); } } 

输出:

 True True False 

理由:

Equals()的默认实现来自ValueType类,它是所有值类型的隐式基类。 您可以通过在结构中定义自己的Equals()方法来覆盖此实现。 当比较不同(动态)类型的对象时, ValueType.Equals()始终返回false。 如果对象具有相同的类型, 则通过为每个字段调用Equals()来比较它们 。 如果其中任何一个返回false,则整个过程停止,最终结果为false。 如果所有逐场比较都返回true,则最终结果为真

如果ReferenceEquals返回false,则显然是在比较两个不同的实例。

如果它被覆盖,则等于可能仍然是真的,但我不认为这是实际问题所在。

我想知道你是如何映射和获取这些对象的,因为正如文档所说, 你永远不会得到两个相同类型的不同对象代表同一个会话中的同一行。

在我从会话中得到childs后,我将他们与会话合并。

 var childs = session.Query(); // Do some stuff foreach (var child in childs) { session.Merge(child); } var parents = childs.Select(x => x.ParentEntity).ToList(); 

似乎合并将实体与会话分离并返回附加到会话的新代理。

它可以修复

 var newChild = (Child)session.Merge(child); // Or: session.Update(child); // (We have session.Clear() in our tests so I can't use this because it makes troubles when you update detached Entity