Why ReferenceEquals and == operator behave different from Equals - c#

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

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

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.

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

Related

xUnit Equal two same collections, same order, same types, returns false

Shouldn't xUnit Equal method return true if two collections are equal meaning have same objects in the same order?
Example:
var result = new List<item>()
{
new item()
{
TypeId = typesEnum.Integer,
Code = "code"
},
new item()
{
TypeId = typesEnum.Integer,
Code = "code2"
}
}
and Assert.Equal(expectedResult, result) returns false.
and I have exactly the same list in expectedResult, checked one by one, every property, type, everything. When I write my own IEqualityComparer and compare every single property of item class in it then the result is true. But default comparer returns false. Is that how it's supposed to work for xUnit? If so the question is how to compare if two collections are equal like equivalent?
Custom comparer looks like this:
internal class ItemComparer : IEqualityComparer<Item>
{
public bool Equals(Item x, Item y)
{
return x.Code.Equals(y.Code) && x.TypeId.Equals(y.TypeId)
}
public int GetHashCode(Item obj)
{
return obj.GetHashCode();
}
}
Here's a link to similiar question:
CLICK
And the answer is that it should work like I think it should without having to write my own comparer. The question is why doesn't it?
I use xUnit 2.4.1
It is not an XUnit issue or particularity, but how C# works. When you have two objects non-primitive, with the same values inside, they are equivalent but not equals - internally they have different memory references for each property. You can even try to compare both using == or .Equals() inside an if statement, and it will return false.
This answer explains very well about this subject
What you could do:
Overwrite comparison operators and use Assert.True(), and compare them in order to return a true;
Use a library that provides a comparison by equivalency, like FluentAssertion: object1.Should().BeEquivalentTo(object2);

Linq to SQL: Unable to Successively insert 2 objects that compare equal

I have a table Size, and I have overloaded GetHashCode and Equals on the corresponding object generated by Linq to SQL.
I am executing the following code:
Size s = new Size();
data_context.Sizes.InsertOnSubmit(s);
data_context.SubmitChanges();
s = new Size
{
Diameter=1
};
data_context.Sizes.InsertOnSubmit(s);
data_context.SubmitChanges();
s = new Size
{
Diameter=1
};
data_context.Sizes.InsertOnSubmit(s);
data_context.SubmitChanges();
On the third SubmitChanges, I get an InvalidOperationException with the message
"Cannot add an entity that already exists."
If I rerun the program I can add the first two again but not the third. I have no clue what's going on, could someone give me a pointer?
If I only override Size.Equals or Size.GetHashCode, this problem doesn't arise, but it does when I override both.
The Equals and GetHashCode override are as follow (but really any kind of method that implement value semantics lead to the same behavior):
public override bool Equals(Object obj)
{
if (obj == null)
{
return false;
}
Size p = obj as Size;
if ((System.Object)p == null)
{
return false;
}
return p.Diameter == Diameter;
}
public override int GetHashCode()
{
return Diameter?.GetHashCode()??0;
}
You said:
I have overloaded GetHashCode and Equals on the corresponding object generated by Linq to SQL.
If you overloaded those so that two Size entities with the same properties are considered equal, then this is working as expected; LINQ to SQL uses equality checks to determine if two objects refer to the same record to keep things in sync.
Why did you override Equals and GetHashCode in the first place? Simply removing those overrides will avoid this issue if you're wanting to be able to insert similar Size objects.

Determine if all the properties in two classes are equal

I have method that updates the properties of a class and then updates that object in the database using a web service. I want to verify that the update succeeded by pulling the new object and comparing it to an object in memory.
Do I need to compare each property or will this determine if they have the same values for all the properties?
var areEqual = objectThatHasChanges.Equals(objectSavedToDatabase);
You will need to compare each property. If these are two reference-type object the equals method will just use default equal implementation which will check the objects are the same instances:
https://msdn.microsoft.com/en-us/library/bsc2ak47(v=vs.110).aspx
If the current instance is a reference type, the Equals(Object) method
tests for reference equality, and a call to the Equals(Object) method
is equivalent to a call to the ReferenceEquals method. Reference
equality means that the object variables that are compared refer to
the same object. The following example illustrates the result of such
a comparison. It defines a Person class, which is a reference type,
and calls the Person class constructor to instantiate two new Person
objects, person1a and person2, which have the same value. It also
assigns person1a to another object variable, person1b. As the output
from the example shows, person1a and person1b are equal because they
reference the same object. However, person1a and person2 are not
equal, although they have the same value.
You should either overload the "Equals" method and write your own which compare each or key properties (like last modify date, revision etc..) or you should write a method which will take these two objects and compare them.
If you have a lot of fields in different objects you can write generic method which uses reflection to iterate through all properties in object and compares with the other. Of course checking first if both objects are of the same type.
If the property names are the same, this is more or less trivial:
private static bool IsEqual(Model1 model, Model2 model2)
{
long changes = 0;
foreach (var pi in typeof(Model1).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var secondModelPi = typeof(Model2).GetProperty(pi.Name, BindingFlags.Instance | BindingFlags.Public);
if (secondModelPi != null)
{
if (!pi.GetValue(model).Equals(secondModelPi.GetValue(model2)))
{
changes++;
}
}
}
return changes == 0;
}
If you really want to check if update is successful then do something in this way:
string query = #"UPDATE [Entities] SET [Value] = [Value] + 1";
// SQL initialization
return (sqlCommand.ExecuteNonQuery() > 0);
ExecuteNonQuery returns the number of affected \ inserted rows. Thus, positive result means that update was successful.
If you, for some reasons, want to get entity from server after update then use the following approach:
string query = #"UPDATE [Entities] SET [Value] = [Value] + 1;
SELECT * FROM [Entities] WHERE [Id] = SCOPE_IDENTITY()"
// SQL initialization
var reader = sqlCommand.ExecuteReader();
while (reader.Read())
{
// Object initialization
}
These ways are better in terms of convenience and performance.
To expound upon #zaitsman's answer, if you want to reuse this for multiple different types you would need to use generic types. I also converted the class to an extension method, as in my mind this should work similar to a LINQ query or .Equals.
//'this' Makes this an extension method if you do not want this to be an extension method just remove the 'this' keyword before model
private static bool IsSame<T,T2>(this T model, T2 model2)
{
long changes = 0;
foreach (var pi in typeof(T).GetProperties(BindingFlags.Instance | BindingFlags.Public))
{
var secondModelPi = typeof(T2).GetProperty(pi.Name, BindingFlags.Instance | BindingFlags.Public);
if (secondModelPi != null)
{
if (!pi.GetValue(model).Equals(secondModelPi.GetValue(model2)))
{
changes++;
}
}
}
return changes == 0;
}
Example Usage
model.IsSame(model2);

Remove one list from another mvc

I have two lists of the same type and I am trying to subtract the information in one list from the other and then save the result into the model.
I have tried two ways of doing it and so far I can't get either to work:
These are the two lists:
List<ApplicationsDetailsModel> AppList = ctx.Database.SqlQuery<ApplicationsDetailsModel>("exec get_applications_r").ToList();
var AppExceptionList = new List<ApplicationsDetailsModel>();
foreach(var g in AnIrrelevantList)
{
AppExceptionList.Add(new ApplicationsDetailsModel()
{
AppNum = g.AppNum,
AppName = g.AppName
});
}
So they now both have different data in the same format.
model.AppList = AppList.Except(AppExceptionList).ToList();
This doesn't bring up any errors but it also doesn't subtract the second list from the first.
var onlyInFirst = AppList.RemoveAll(a => AppExceptionList.Any(b => AppList == AppExceptionList));
I got this idea from this question.
Anyone know where I am going wrong?
The instances are not the same and are therefore not found to be equal by Except since it's checking for reference equal (which is obviously never going to be the case). For your situation you need to write a custom equality comparer... I've taken a stab at it here...
public class ApplicationsDetailsModelEqualityComparer : IEqualityComparer<ApplicationsDetailsModel>
{
public bool Equals(ApplicationsDetailsModel x, ApplicationsDetailsModel y)
{
return x.AppNum == y.AppNum && x.AppName == y.AppName;
}
public int GetHashCode(ApplicationsDetailsModel obj)
{
int hashCode = (obj.AppName != null ? obj.AppName.GetHashCode() : 0);
hashCode = (hashCode * 397) ^ obj.AppNum.GetHashCode();
return hashCode;
}
}
Usage...
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelEqualityComparer()).ToList();
Note that I'm assuming your AppNum and AppName together uniquely identify your objects in your list.
The Except method doesn't know how to compare two objects of type ApplicationsDetailsModel. You need to tell him explicitly, using an IEqualityComparer :
public class ApplicationsDetailsModelComparer : IEqualityComparer<ApplicationsDetailsModel> {
public bool Equals(ApplicationsDetailsModel first, ApplicationsDetailsModel second) {
return first.AppNum == second.AppNum;
}
public int GetHashCode(ApplicationsDetailsModel applicationsDetailsModel) {
return applicationsDetailsModel.AppNum.GetHashCode();
}
}
Then, you use it like this :
model.AppList = AppList.Except(AppExceptionList, new ApplicationsDetailsModelComparer ()).ToList();
If AppNum isn't an unique value in your collection (like a primary key), feel free to adapt the comparer class to your needs.
jgauffin's answer on the question that you linked to sums it up:
http://stackoverflow.com/a/13361682/89092
Except requires that Equals and GetHashCode is implemented in the traversed class.
The problem is that the Except method does not now how to compare instances of ApplicationsDetailsModel
You should implement GetHashCode in ApplicationsDetailsModel to create a way to uniquely identify an instance
You should implement Equals in ApplicationsDetailsModel and use the result of GetHashCode to return whether or no the instances should be considered "Equal". It is probably best to do this by implementing the IEquatable interface: http://msdn.microsoft.com/en-us/library/ms131187(v=vs.110).aspx
When you perform these steps, the Except method will work as expected

Retrieved Dictionary Key Not Found

I have a SortedDictionary declared like such:
SortedDictionary<MyObject,IMyInterface> dict = new SortedDictionary<MyObject,IMyInterface>();
When its populated with values, if I grab any key from the dictionary and then try to reference it immediately after, I get a KeyNotFoundException:
MyObject myObj = dict.Keys.First();
var value = dict[myObj]; // This line throws a KeyNotFoundException
As I hover over the dictionary (after the error) with the debugger, I can clearly see the same key that I tried to reference is in fact contained in the dictionary. I'm populating the dictionary using a ReadOnlyCollection of MyObjects. Perhaps something odd is happening there? I tried overriding the == operator and Equals methods to get the explicit comparison I wanted, but no such luck. That really shouldn't matter since I'm actually getting a key directly from the Dictionary then querying the Dictionary using that same key. I can't figure out what's causing this. Has anyone ever seen this behavior?
EDIT 1
In overriding Equals I also overloaded (as MS recommends) GetHashCode as well. Here's the implementation of MyObject for anyone interested:
public class MyObject
{
public string UserName { get; set;}
public UInt64 UserID { get; set;}
public override bool Equals(object obj)
{
if (obj == null || GetType()!= obj.GetType())
{
return false;
}
// Return true if the fields match:
return this.Equals((MyObject)obj);
}
public bool Equals(MyObject other)
{
// Return true if the fields match
return this.UserID == other.UserID;
}
public override int GetHashCode()
{
return (int)this.UserID;
}
public static bool operator ==( MyObject a, MyObject b)
{
// If both are null, or both are same instance, return true.
if (System.Object.ReferenceEquals(a, b))
{
return true;
}
// If one is null, but not both, return false.
if (((object)a == null) || ((object)b == null))
{
return false;
}
// Return true if the fields match:
return a.UserID == b.UserID
}
public static bool operator !=( MyObject a, MyObject b)
{
return !(a == b);
}
}
What I noticed from debugging is that if I add a quick watch (after the KeyNotFoundException is thrown) for the expression:
dict.ElementAt(0).Key == value;
it returns true. How can this be?
EDIT 2
So the problem ended up being because SortedDictionary (and Dictionary as well) are not thread-safe. There was a background thread that was performing some operations on the dictionary which seem to be triggering a resort of the collection (adding items to the collection would do this). At the same time, when the dictionary iterated through the values to find my key, the collection was being changed and it was not finding my key even though it was there.
Sorry for all of you who asked for code on this one, I'm currently debugging an application that I inherited and I didn't realize this was going on on a timed, background thread. As such, I thought I copied and pasted all the relevant code, but I didn't realize there was another thread running behind everything manipulating the collection.
It appears that the problem ended up being because SortedDictionary is not thread-safe. There was a background thread that was performing some operations on the dictionary (adding items to the collection) which seems to be triggering a resort of the collection. At the same time, when the dictionary was attempting to iterate through the values to find my key, the collection was being changed and resorted, rendering the enumerator invalid, and it was not finding my key even though it was there.
I have a suspicion - it's possible that you're changing the UserID of the key after insertion. For example, this would demonstrate the problem:
var key = new MyObject { UserId = 10 };
var dictionary = new Dictionary<MyObject, string>();
dictionary[key] = "foo";
key.UserId = 20; // This will change the hash code
var value = dict[key]; // Bang!
You shouldn't change properties involved in equality/hash-code considerations for an object which is being used as the key in a hash-based collection. Ideally, change your code so that this can't be changed - make UserId readonly, initialized on construction.
The above definitely would cause a problem - but it's possible that it's not the same as the problem you're seeing, of course.
In addition to overloading == and Equals, make sure you override GetHashCode with a suitable hash function. In particular, see this specification from the documentation:
If two objects compare as equal, the GetHashCode method for each object must return the same value. However, if two objects do not
compare as equal, the GetHashCode methods for the two objects do not
have to return different values.
The GetHashCode method for an object must consistently return the same hash code as long as there is no modification to the object state
that determines the return value of the object's Equals method. Note
that this is true only for the current execution of an application,
and that a different hash code can be returned if the application is
run again.
For the best performance, a hash function should generate an even distribution for all input, including input that is heavily clustered.
An implication is that small modifications to object state should
result in large modifications to the resulting hash code for best hash
table performance.
Hash functions should be inexpensive to compute.
The GetHashCode method should not throw exceptions.
I agree with Jon Skeet's suspicion that you're somehow unintentionally modifying UserID property after it's added as a key. But since the only property that's important for testing equality in MyObject is UserID (and therefore that's the only property that the Dictionary cares about), I'd recommend refactoring your code to use a simple Dictionary<ulong, IMyInterface> instead:
Dictionary<ulong, IMyInterface> dict = new Dictionary<string, IMyInterface>();
ulong userID = dict.Keys.First();
var value = dict[userID];

Categories

Resources