【问题标题】:Why ReferenceEquals and == operator behave different from Equals为什么 ReferenceEquals 和 == 运算符的行为与 Equals 不同
【发布时间】:2012-01-10 18:08:09
【问题描述】:

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

  • ReferenceEquals(first, second) - false。
  • 第一个 == 第二个 - 错误
  • 等于(第一,第二) - 真。

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

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

还有:

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

那么为什么不是所有的相等方法都返回 true 呢?


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

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

【问题讨论】:

  • 您的问题与您的标题不符 - 您的示例显示 == 和 ReferenceEquals 的行为方式相同。
  • 我的猜测是两个单独的代理“指向”同一个实例,因此代理不满足引用相等,但 Equals 方法被编组,因此它们被报告为相等。
  • 如何从会话中获取这两个对象?以我的经验, == 平等可靠地工作。所以我的猜测是,要么 Nhibernate 认为这两个实体实际上代表不同的数据库行,要么它们属于不同的会话。

标签: c# .net nhibernate orm proxy


【解决方案1】:

从会话中获得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

【讨论】:

  • 如果您提到您使用的是Merge,那么对话会更短:-)
  • @DiegoMijelshon,我说的对吗? Merge 是否将代理从会话上下文中分离出来?我在nhusers群里问过:groups.google.com/group/nhusers/browse_frm/thread/…没有人回复,在文档里也找不到。
  • 我不知道 //Do some stuff 块中有什么(同样,你隐藏了可能重要的细节),但我不明白你想用 Merge 做什么。跨度>
  • @DiegoMijelshon,你说得对,我的公司不允许我在这里写代码... :( 但是真的没有什么特别的,只有查询和数据更改. 我使用 Merge 是因为在 testing 中 Proxy 是分离的,因为在我们调用该方法之前有一个 session.Clear() 所以 session.Update 在这种情况下会抛出异常... =( ,你有更好的解决方案吗?(除了删除愚蠢的会话。清除 {I can't delete it, not my call...})
  • 在这一点上,我无能为力。您的实际问题与您最初描述的完全不同,主要是由于 NHibernate 不正确造成的。使用 session.Clear 会破坏所有已声明的关于对象身份的保证。
【解决方案2】:

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

如果被覆盖,Equals 可能仍然是正确的,但我认为这不是实际问题所在。

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

【讨论】:

  • 更新了我的帖子。我不认为映射中有什么有趣的东西。也许在查询中
  • 好的,所以你得到了parents 的列表,其中一些代表同一行(即具有相同的 POID),但不是同一个对象。是这样吗?
  • 是的,故事就是这样。我按照您在另一篇文章中的建议删除了 Equals 和 GetHashCode ,看看会发生什么......大声笑
  • 您可以添加您的映射和示例比较吗?
  • 直到下周...您所说的样本比较是什么意思
【解决方案3】:

编辑

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


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

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

【讨论】:

    猜你喜欢
    • 2015-11-18
    • 2013-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-04
    相关资源
    最近更新 更多