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

时间:2011-12-01 15:39:37

标签: c# .net nhibernate orm proxy

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

  • ReferenceEquals(第一,第二) - false。
  • first == second - false
  • 等于(第一,第二) - 是真的。

这更奇怪,因为它们都存在于同一会话环境中并且根据Nhibernate docs

  

NHibernate只保证身份(a == b,默认值   在单个ISession中实现Equals())!`

  

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

那么为什么不是所有的等式都返回true?


更新
我通过这种方式获得了enteties,查询ChildEntity的会话并使用Linq的select获取父母实体,类似于:

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

3 个答案:

答案 0 :(得分:1)

修改

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


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

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,则最终结果为真

答案 1 :(得分:0)

如果ReferenceEquals返回false,则表明您正在比较两个不同的实例。

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

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

答案 2 :(得分:0)

从会话中获得childs后,我将其与会话合并。

var childs = session.Query<Child>();
// 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