Why ReferenceEquals and == operator behave differe

2020-04-08 11:12发布

I have an Entity that doesn't override any of the equality members\operators.
When comparing two proxies of them (I got them from the Nhibernate session) the result changes according to the equality method:

  • ReferenceEquals(first, second) - false.
  • first == second - false
  • Equals(first, second) - true.

This is even more weird as they both exist in the same session context and according to the Nhibernate docs:

NHibernate only guarantees identity ( a == b , the default implementation of Equals()) inside a single ISession!`

And:

The instance is currently associated with a persistence context. It has a persistent identity (primary key value) and, perhaps, a corresponding row in the database. For a particular persistence context, NHibernate guarantees that persistent identity is equivalent to CLR identity (in-memory location of the object).

So why not all of the equality methods return true?


Update:
I get the enteties this way, Query the session for ChildEntity and get the Parents Entities with Linq's select, similar to this:

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

3条回答
不美不萌又怎样
2楼-- · 2020-04-08 11:59

If ReferenceEquals returns false, you are clearly comparing two different instances.

Equals might still be true if it's overridden, but I don't think that's where the actual problem is.

I'd like to know how you're mapping and getting those objects, because as the docs say, you can never get two different objects of the same type representing the same row in the same session.

查看更多
狗以群分
3楼-- · 2020-04-08 12:01

After I get childs from the session I Merge them with the session.

var childs = session.Query<Child>();
// Do some stuff
foreach (var child in childs)
{
    session.Merge(child);
}

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

It appear that the merge detached the entity from the session and return a new Proxy attached to the session.

It can be fixed with

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
查看更多
成全新的幸福
4楼-- · 2020-04-08 12:04

Edit

You might be using a struct? See below


I suppose reference types show the behaviour you expect:

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));
} }

Prints:

False
False
False
False

For structs, things are different (commeting out the a==b test, which doesn't compile for structs:)

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));
} }

Output:

True
True
False

Rationale:

The default implementation of Equals() comes from class ValueType, which is implicit base class of all value types. You may override this implementation by defining your own Equals() method in your struct. ValueType.Equals() always returns false when one compares objects of different (dynamic) types. If objects are of the same type, it compares them by calling Equals() for each field. If any of these returns false, the whole process is stopped, and final result is false. If all field-by-field comparisons return true, final result is true

查看更多
登录 后发表回答