Checking list of objects for differences - c#

I have the following two lists:
List<MyObject> oldList = new List<MyObject>();
oldList.Add(new MyObject { Id = 1, Name = "hello" });
oldList.Add(New MyObject { Id = 2, Name = "world" });
List<MyObject> newList = new List<MyObject>();
newList.Add(new MyObject { Id = 1, Name = "Hello" });
newList.Add(new MyObject { Id = 3, Name = "World" });
newList.Add(new MyObject { Id = 4, Name = "hello" });
I would like to write something to compare the two lists and return boolean true if the lists are different.
For example, the lists above are different in the following ways:
Id's don't exactly match
Counts don't match
In cases where Id's do match, the Name's don't exactly match (case-sensitive)
I have tried the following:
if (oldList != newList)
And:
if (!oldList.SequenceEqual(newList))
However, both produce inaccurate results. I understand I can create a class of type IEqualityComparer which implements a HashSet comparison; but I also read that it may not work for my case... Can someone shed any light on how to compare two objects to detect the types of changes I have specified?

As you've said, you only need to implement the correct IEquatable<MyObject> interface in your MyObject, or implement an IEqualityComparer<MyObject>
/// <summary>
/// Fully equatable MyObject
/// </summary>
public class MyObject : IEquatable<MyObject>
{
public int Id { get; set; }
public string Name { get; set; }
public override bool Equals(object obj)
{
// obj is object, so we can use its == operator
if (obj == null)
{
return false;
}
MyObject other = obj as MyObject;
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
public bool Equals(MyObject other)
{
if (object.ReferenceEquals(other, null))
{
return false;
}
return this.InnerEquals(other);
}
private bool InnerEquals(MyObject other)
{
// Here we know that other != null;
if (object.ReferenceEquals(this, other))
{
return true;
}
return this.Id == other.Id && this.Name == other.Name;
}
public override int GetHashCode()
{
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + this.Id.GetHashCode();
hash = hash * 23 + (this.Name != null ? this.Name.GetHashCode() : 0);
return hash;
}
}
}
and then you can use
if (!oldList.SequenceEqual(newList))
Note that this will compare element order! If you change element order, then the comparison will return false
Or you can use an "external" IEqualityComparer<MyObject>
public class MyObjectEqualityComparer : IEqualityComparer<MyObject>
{
public static readonly MyObjectEqualityComparer Default = new MyObjectEqualityComparer();
protected MyObjectEqualityComparer()
{
}
public bool Equals(MyObject x, MyObject y)
{
if (object.ReferenceEquals(x, null))
{
return object.ReferenceEquals(y, null);
}
if (object.ReferenceEquals(y, null))
{
return false;
}
// Here we know that x != null && y != null;
if (object.ReferenceEquals(x, y))
{
return true;
}
return x.Id == y.Id && x.Name == y.Name;
}
public int GetHashCode(MyObject obj)
{
if (obj == null)
{
return 0;
}
unchecked
{
// From http://stackoverflow.com/a/263416/613130
int hash = 17;
hash = hash * 23 + obj.Id.GetHashCode();
hash = hash * 23 + (obj.Name != null ? obj.Name.GetHashCode() : 0);
return hash;
}
}
}
use it like
if (!oldList.SequenceEqual(newList, MyObjectEqualityComparer.Default))
Note that there are various schools of thought on how exactly to write equality comparers, and there is a little caveat: if you override the operator== you must be very very wary of not using it inside your comparator :-)
A classical example of wrong code, when the operator== is overloaded
public bool Equals(MyObject other)
{
// BOOOM!!! StackOverflowException!
// Equals will call operator== that will probably call
// Equals back! and so on and so on.
if (other == null)
{
return false;
}
return this.InnerEquals(other);
}
So it is better to do object.ReferenceEquals(something, someotherthing) that does reference comparison.
Then there is the problem of null handling with properties:
The hash of Name (a string) is written like this:
hash = hash * 23 + obj.Name != null ? obj.Name.GetHashCode() : 0
so that if obj.Name is null the code doesn't expode in a NullReferenceException. Automatically generated code for anonymous objects use another way:
hash = hash * 23 + EqualityComparer<string>.Default.GetHashCode(obj.Name);
The EqualityComparer<string>.Default is safe to use, even with null values.
For the Equals comparison of properties, the automatically generated code for anonymous objects uses another funny trick:
&& EqualityComparer<string>.Default.Equals(this.Name, obj.Name);
so it uses EqualityComparer<string>.Default.Equals, that then correctly uses the various methods/interfaces to compare objects.

Related

What's the best way to compare all properties of two objects? [duplicate]

I have two complex objects like Object1 and Object2. They have around 5 levels of child objects.
I need the fastest method to say if they are same or not.
How could this be done in C# 4.0?
Implement IEquatable<T> (typically in conjunction with overriding the inherited Object.Equals and Object.GetHashCode methods) on all your custom types. In the case of composite types, invoke the contained types’ Equals method within the containing types. For contained collections, use the SequenceEqual extension method, which internally calls IEquatable<T>.Equals or Object.Equals on each element. This approach will obviously require you to extend your types’ definitions, but its results are faster than any generic solutions involving serialization.
Edit: Here is a contrived example with three levels of nesting.
For value types, you can typically just call their Equals method. Even if the fields or properties were never explicitly assigned, they would still have a default value.
For reference types, you should first call ReferenceEquals, which checks for reference equality – this would serve as an efficiency boost when you happen to be referencing the same object. It would also handle cases where both references are null. If that check fails, confirm that your instance's field or property is not null (to avoid NullReferenceException) and call its Equals method. Since our members are properly typed, the IEquatable<T>.Equals method gets called directly, bypassing the overridden Object.Equals method (whose execution would be marginally slower due to the type cast).
When you override Object.Equals, you’re also expected to override Object.GetHashCode; I didn’t do so below for the sake of conciseness.
public class Person : IEquatable<Person>
{
public int Age { get; set; }
public string FirstName { get; set; }
public Address Address { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public bool Equals(Person other)
{
if (other == null)
return false;
return this.Age.Equals(other.Age) &&
(
object.ReferenceEquals(this.FirstName, other.FirstName) ||
this.FirstName != null &&
this.FirstName.Equals(other.FirstName)
) &&
(
object.ReferenceEquals(this.Address, other.Address) ||
this.Address != null &&
this.Address.Equals(other.Address)
);
}
}
public class Address : IEquatable<Address>
{
public int HouseNo { get; set; }
public string Street { get; set; }
public City City { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Address);
}
public bool Equals(Address other)
{
if (other == null)
return false;
return this.HouseNo.Equals(other.HouseNo) &&
(
object.ReferenceEquals(this.Street, other.Street) ||
this.Street != null &&
this.Street.Equals(other.Street)
) &&
(
object.ReferenceEquals(this.City, other.City) ||
this.City != null &&
this.City.Equals(other.City)
);
}
}
public class City : IEquatable<City>
{
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as City);
}
public bool Equals(City other)
{
if (other == null)
return false;
return
object.ReferenceEquals(this.Name, other.Name) ||
this.Name != null &&
this.Name.Equals(other.Name);
}
}
Update: This answer was written several years ago. Since then, I've started to lean away from implementing IEquality<T> for mutable types for such scenarios. There are two notions of equality: identity and equivalence. At a memory representation level, these are popularly distinguished as “reference equality” and “value equality” (see Equality Comparisons). However, the same distinction can also apply at a domain level. Suppose that your Person class has a PersonId property, unique per distinct real-world person. Should two objects with the same PersonId but different Age values be considered equal or different? The answer above assumes that one is after equivalence. However, there are many usages of the IEquality<T> interface, such as collections, that assume that such implementations provide for identity. For example, if you're populating a HashSet<T>, you would typically expect a TryGetValue(T,T) call to return existing elements that share merely the identity of your argument, not necessarily equivalent elements whose contents are completely the same. This notion is enforced by the notes on GetHashCode:
In general, for mutable reference types, you should override GetHashCode() only if:
You can compute the hash code from fields that are not mutable; or
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
Serialize both objects and compare the resulting strings
You can use extension method, recursion to resolve this problem:
public static bool DeepCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
//Compare two object's class, return false if they are difference
if (obj.GetType() != another.GetType()) return false;
var result = true;
//Get all properties of obj
//And compare each other
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
if (!objValue.Equals(anotherValue)) result = false;
}
return result;
}
public static bool CompareEx(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
//properties: int, double, DateTime, etc, not class
if (!obj.GetType().IsClass) return obj.Equals(another);
var result = true;
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
//Recursion
if (!objValue.DeepCompare(anotherValue)) result = false;
}
return result;
}
or compare by using Json (if object is very complex)
You can use Newtonsoft.Json:
public static bool JsonCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
var objJson = JsonConvert.SerializeObject(obj);
var anotherJson = JsonConvert.SerializeObject(another);
return objJson == anotherJson;
}
If you don't want to implement IEquatable, you can always use Reflection to compare all the properties:
- if they're value type, just compare them
-if they are reference type, call the function recursively to compare its "inner" properties.
I'm not thinking about performace, but about simplicity. It depends, however on the exact design of your objects. It could get complicated depending on your objects shape (for example if there are cyclic dependencies between properties). There are, however, several solutions out there that you can use, like this one:
Compare .NET objects
Another option is to serialize the object as text, for example using JSON.NET, and comparing the serialization result. (JSON.NET can handle Cyclic dependencies between properties).
I don't know if by fastest you mean the fastest way to implement it or a code that runs fast. You should not optimize before knowing if you need to. Premature optimization is the root of all evil
Serialize both objects and compare the resulting strings by #JoelFan
So to do this, create a static class like so and use Extensions to extend ALL objects (so you can pass anytype of object, collection, etc into the method)
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
public static class MySerializer
{
public static string Serialize(this object obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
}
Once you reference this static class in any other file, you can do this:
Person p = new Person { Firstname = "Jason", LastName = "Argonauts" };
Person p2 = new Person { Firstname = "Jason", LastName = "Argonaut" };
//assuming you have already created a class person!
string personString = p.Serialize();
string person2String = p2.Serialize();
Now you can simply use .Equals to compare them.
I use this for checking if objects are in collections too. It works really well.
If you have a requirement where you want the class which is immutable. I mean that none of the properties can be modified once it's been created. In that case, C# 9 have a feature which is called a record.
You can easily compare records by values and types is they are equal.
public record Person
{
public string LastName { get; }
public string FirstName { get; }
public Person(string first, string last) => (FirstName, LastName) = (first, last);
}
var person1 = new Person("Bill", "Wagner");
var person2 = new Person("Bill", "Wagner");
Console.WriteLine(person1 == person2); // true
You can now use json.net. Just go on Nuget and install it.
And you can do something like this:
public bool Equals(SamplesItem sampleToCompare)
{
string myself = JsonConvert.SerializeObject(this);
string other = JsonConvert.SerializeObject(sampleToCompare);
return myself == other;
}
You could perhaps make a extension method for object if you wanted to get fancier. Please note this only compares the public properties. And if you wanted to ignore a public property when you do the comparison you could use the [JsonIgnore] attribute.
Serialize both objects, then calculate Hash Code, then compare.
I'll assume you are not referring to literally the same objects
Object1 == Object2
You might be thinking about doing a memory comparison between the two
memcmp(Object1, Object2, sizeof(Object.GetType())
But that's not even real code in c# :). Because all of your data is probably created on the heap, the memory is not contiguous and you can't just compare the equality of two objects in an agnostic manner. You're going to have to compare each value, one at a time, in a custom way.
Consider adding the IEquatable<T> interface to your class, and define a custom Equals method for your type. Then, in that method, manual test each value. Add IEquatable<T> again on enclosed types if you can and repeat the process.
class Foo : IEquatable<Foo>
{
public bool Equals(Foo other)
{
/* check all the values */
return false;
}
}
Based off a few answers already given here I decided to mostly back JoelFan's answer. I love extension methods and these have been working great for me when none of the other solutions would using them to compare my complex classes.
Extension Methods
using System.IO;
using System.Xml.Serialization;
static class ObjectHelpers
{
public static string SerializeObject<T>(this T toSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
using (StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
}
public static bool EqualTo(this object obj, object toCompare)
{
if (obj.SerializeObject() == toCompare.SerializeObject())
return true;
else
return false;
}
public static bool IsBlank<T>(this T obj) where T: new()
{
T blank = new T();
T newObj = ((T)obj);
if (newObj.SerializeObject() == blank.SerializeObject())
return true;
else
return false;
}
}
Usage Examples
if (record.IsBlank())
throw new Exception("Record found is blank.");
if (record.EqualTo(new record()))
throw new Exception("Record found is blank.");
I would say that:
Object1.Equals(Object2)
would be what you're looking for. That's if you're looking to see if the objects are the same, which is what you seem to be asking.
If you want to check to see if all the child objects are the same, run them through a loop with the Equals() method.
I found this below function for comparing objects.
static bool Compare<T>(T Object1, T object2)
{
//Get the type of the object
Type type = typeof(T);
//return false if any of the object is false
if (object.Equals(Object1, default(T)) || object.Equals(object2, default(T)))
return false;
//Loop through each properties inside class and get values for the property from both the objects and compare
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
if (property.Name != "ExtensionData")
{
string Object1Value = string.Empty;
string Object2Value = string.Empty;
if (type.GetProperty(property.Name).GetValue(Object1, null) != null)
Object1Value = type.GetProperty(property.Name).GetValue(Object1, null).ToString();
if (type.GetProperty(property.Name).GetValue(object2, null) != null)
Object2Value = type.GetProperty(property.Name).GetValue(object2, null).ToString();
if (Object1Value.Trim() != Object2Value.Trim())
{
return false;
}
}
}
return true;
}
I am using it and it is working fine for me.
Thanks to the example of Jonathan. I expanded it for all cases (arrays, lists, dictionaries, primitive types).
This is a comparison without serialization and does not require the implementation of any interfaces for compared objects.
/// <summary>Returns description of difference or empty value if equal</summary>
public static string Compare(object obj1, object obj2, string path = "")
{
string path1 = string.IsNullOrEmpty(path) ? "" : path + ": ";
if (obj1 == null && obj2 != null)
return path1 + "null != not null";
else if (obj2 == null && obj1 != null)
return path1 + "not null != null";
else if (obj1 == null && obj2 == null)
return null;
if (!obj1.GetType().Equals(obj2.GetType()))
return "different types: " + obj1.GetType() + " and " + obj2.GetType();
Type type = obj1.GetType();
if (path == "")
path = type.Name;
if (type.IsPrimitive || typeof(string).Equals(type))
{
if (!obj1.Equals(obj2))
return path1 + "'" + obj1 + "' != '" + obj2 + "'";
return null;
}
if (type.IsArray)
{
Array first = obj1 as Array;
Array second = obj2 as Array;
if (first.Length != second.Length)
return path1 + "array size differs (" + first.Length + " vs " + second.Length + ")";
var en = first.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
string res = Compare(en.Current, second.GetValue(i), path);
if (res != null)
return res + " (Index " + i + ")";
i++;
}
}
else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
{
System.Collections.IEnumerable first = obj1 as System.Collections.IEnumerable;
System.Collections.IEnumerable second = obj2 as System.Collections.IEnumerable;
var en = first.GetEnumerator();
var en2 = second.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
if (!en2.MoveNext())
return path + ": enumerable size differs";
string res = Compare(en.Current, en2.Current, path);
if (res != null)
return res + " (Index " + i + ")";
i++;
}
}
else
{
foreach (PropertyInfo pi in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
try
{
var val = pi.GetValue(obj1);
var tval = pi.GetValue(obj2);
if (path.EndsWith("." + pi.Name))
return null;
var pathNew = (path.Length == 0 ? "" : path + ".") + pi.Name;
string res = Compare(val, tval, pathNew);
if (res != null)
return res;
}
catch (TargetParameterCountException)
{
//index property
}
}
foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = fi.GetValue(obj1);
var tval = fi.GetValue(obj2);
if (path.EndsWith("." + fi.Name))
return null;
var pathNew = (path.Length == 0 ? "" : path + ".") + fi.Name;
string res = Compare(val, tval, pathNew);
if (res != null)
return res;
}
}
return null;
}
For easy copying of the code created repository
public class GetObjectsComparison
{
public object FirstObject, SecondObject;
public BindingFlags BindingFlagsConditions= BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
}
public struct SetObjectsComparison
{
public FieldInfo SecondObjectFieldInfo;
public dynamic FirstObjectFieldInfoValue, SecondObjectFieldInfoValue;
public bool ErrorFound;
public GetObjectsComparison GetObjectsComparison;
}
private static bool ObjectsComparison(GetObjectsComparison GetObjectsComparison)
{
GetObjectsComparison FunctionGet = GetObjectsComparison;
SetObjectsComparison FunctionSet = new SetObjectsComparison();
if (FunctionSet.ErrorFound==false)
foreach (FieldInfo FirstObjectFieldInfo in FunctionGet.FirstObject.GetType().GetFields(FunctionGet.BindingFlagsConditions))
{
FunctionSet.SecondObjectFieldInfo =
FunctionGet.SecondObject.GetType().GetField(FirstObjectFieldInfo.Name, FunctionGet.BindingFlagsConditions);
FunctionSet.FirstObjectFieldInfoValue = FirstObjectFieldInfo.GetValue(FunctionGet.FirstObject);
FunctionSet.SecondObjectFieldInfoValue = FunctionSet.SecondObjectFieldInfo.GetValue(FunctionGet.SecondObject);
if (FirstObjectFieldInfo.FieldType.IsNested)
{
FunctionSet.GetObjectsComparison =
new GetObjectsComparison()
{
FirstObject = FunctionSet.FirstObjectFieldInfoValue
,
SecondObject = FunctionSet.SecondObjectFieldInfoValue
};
if (!ObjectsComparison(FunctionSet.GetObjectsComparison))
{
FunctionSet.ErrorFound = true;
break;
}
}
else if (FunctionSet.FirstObjectFieldInfoValue != FunctionSet.SecondObjectFieldInfoValue)
{
FunctionSet.ErrorFound = true;
break;
}
}
return !FunctionSet.ErrorFound;
}
Generic Extension Method
public static class GenericExtensions
{
public static bool DeepCompare<T>(this T objA, T objB)
{
if (typeof(T).IsValueType)
return objA.Equals(objB);
if (ReferenceEquals(objA, objB))
return true;
if ((objA == null) || (objB == null))
return false;
if (typeof(T) is IEnumerable)
{
var enumerableA = (IEnumerable<T>) objA;
var enumerableB = (IEnumerable<T>) objB;
if (enumerableA.Count() != enumerableB.Count())
return false;
using (var enumeratorA = enumerableA.GetEnumerator())
using (var enumeratorB = enumerableB.GetEnumerator())
{
while (true)
{
bool moveNextA = enumeratorA.MoveNext();
bool moveNextB = enumeratorB.MoveNext();
if (!moveNextA || !moveNextB)
break;
var currentA = enumeratorA.Current;
var currentB = enumeratorB.Current;
if (!currentA.DeepCompare<T>(currentB))
return false;
}
return true;
}
}
foreach (var property in objA.GetType().GetProperties())
{
var valueA = property.GetValue(objA);
var valueB = property.GetValue(objB);
if (!valueA.DeepCompare(valueB))
return false;
}
return true;
}
}
One way to do this would be to override Equals() on each type involved. For example, your top level object would override Equals() to call the Equals() method of all 5 child objects. Those objects should all override Equals() as well, assuming they are custom objects, and so on until the entire hierarchy could be compared by just performing an equality check on the top level objects.
Use IEquatable<T> Interface which has a method Equals.
To return each property updated:
public IEnumerable<string> GetPropsUpdated(T oldModel, T newModel)
{
var diff = new List<string>();
foreach (var prop in oldModel.GetType().GetProperties())
{
var oldValue = prop.GetValue(oldModel);
var newValue = prop.GetValue(newModel);
if (oldValue == null && newValue == null)
continue;
if (oldValue == null && newValue != null
|| oldValue != null && newValue == null)
{
diff.Add(prop.Name);
continue;
}
var oldPropHashed = oldValue.GetHashCode();
var newPropHashed = newValue.GetHashCode();
if (!oldPropHashed.Equals(newPropHashed))
diff.Add(prop.Name);
}
return diff;
}

Compare equality of two objects based on dictionaries

I have two objects with these definitions:
public static Dictionary<string, Container> cont1 = new Dictionary<string, Container>();
public static Dictionary<string, Container> cont2 = new Dictionary<string, Container>();
The schema of Container class is as following:
public class Container
{
public string IDx { get; set; }
public string IDy { get; set; }
public string Name { get; set; }
public Dictionary<string, Sub> Subs = new Dictionary<string, Sub>();
}
public class Sub
{
public string Namex { get; set; }
public string Namey { get; set; }
public string Value { get; set; }
public Dictionary<string, string> Paths { get; set; }
}
My question is: How can I deep check the equity of cont1 and cont2? I mean the equality of every member and value even deep down within Subs objects;
Is there any functionality in c# for such situations or I have to write a custom method for checking equality based on the structure of the objects myself;
Second Question: I can obviate the equality problem if I can create two different copies of Products; I mean say we have a base Container object with all the members and values and then create two separate copies of Container, namely cont1 and cont2 which changing a value in cont1 wont change the same value in cont2.
Note1: this method for cloning is not working:
cont2 = new Dictionary<string, Container>(cont1);
Note2: most of the proposed methods in other answers are based on a one level dictionary (using loops or LINQ for checking) and not such a case when we have properties and dictionary objects (which having their own properties) within the object.
A Dictionary is a Sequence, so in general what you're probably looking for is Enumerable<T>.SequenceEquals which allows passing in an IEquityComparer<T>.
Your sequence (Dictionary) is an IEnumerable<KeyValuePair<string,Container>> so you need an comparer which implements IEquityComparer<IEnumerable<KeyValuePair<string,Container>>> (Thats a lot of angle braces!).
var equal = cont1.SequenceEquals(cont2, new StringContainerPairEquityComparer());
Note that the order of elements dictionaries is not guaranteed, so to use the method properly you should probably use OrderBy before comparing sequences - however this adds to the inefficiency of this method.
For your second question, what you're trying to do is Clone the dictionary. In general your Container should implement ICloneable interface, which you can then use to create a copy
var cont2 = cont1.ToDictionary(k => k.Key, v => v.Value.Clone());
Yes, you have to write a custom method for checking equality based on the structure of the objects yourself. I would provide a custom IEqualityComparer<Container> and an IEqualityComparer<Sub> like here (GetHashCode implementation based on this):
public class ContainerCheck : IEqualityComparer<Container>
{
private SubCheck subChecker = new SubCheck();
public bool Equals(Container x, Container y)
{
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
if (x.IDx != y.IDx || x.IDy != y.IDy || x.Name != y.Name)
return false;
// check dictionary
if (ReferenceEquals(x.Subs, y.Subs))
return true;
if (x.Subs == null || y.Subs == null || x.Subs.Count != y.Subs.Count)
return false;
foreach (var kv in x.Subs)
if (!y.Subs.ContainsKey(kv.Key) || subChecker.Equals(y.Subs[kv.Key], kv.Value))
return false;
return true;
}
public int GetHashCode(Container obj)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + obj.IDx.GetHashCode();
hash = hash * 23 + obj.IDy.GetHashCode();
hash = hash * 23 + obj.Name.GetHashCode();
foreach (var kv in obj.Subs)
{
hash = hash * 23 + kv.Key.GetHashCode();
hash = hash * 23 + subChecker.GetHashCode(kv.Value);
}
return hash;
}
}
}
public class SubCheck : IEqualityComparer<Sub>
{
public bool Equals(Sub x, Sub y)
{
if (ReferenceEquals(x, y))
return true;
if (x == null || y == null)
return false;
if (x.Namex != y.Namex || x.Namey != y.Namey || x.Value != y.Value)
return false;
// check dictionary
if (ReferenceEquals(x.Paths, y.Paths))
return true;
if (x.Paths == null || y.Paths == null || x.Paths.Count != y.Paths.Count)
return false;
foreach(var kv in x.Paths)
if (!y.Paths.ContainsKey(kv.Key) || y.Paths[kv.Key] != kv.Value)
return false;
return true;
}
public int GetHashCode(Sub obj)
{
unchecked // Overflow is fine, just wrap
{
int hash = 17;
// Suitable nullity checks etc, of course :)
hash = hash * 23 + obj.Namex.GetHashCode();
hash = hash * 23 + obj.Namey.GetHashCode();
hash = hash * 23 + obj.Value.GetHashCode();
foreach (var kv in obj.Paths)
{
hash = hash * 23 + kv.Key.GetHashCode();
hash = hash*23 + kv.Value.GetHashCode();
}
return hash;
}
}
}
This should deep check all properties and the dictionaries. Then you could use following loop to compare both dictionaries with each other:
bool equal = true;
var allKeys = cont1.Keys.Concat(cont2.Keys).ToList();
var containerChecker = new ContainerCheck();
foreach (string key in allKeys)
{
Container c1;
Container c2;
if (!cont1.TryGetValue(key, out c1) || !cont2.TryGetValue(key, out c2))
{
equal = false;
}
else
{
// deep check both containers
if (!containerChecker.Equals(c1, c2))
equal = false;
}
if(!equal)
break; // or collect differences
}

UnitTesting List<T> of custom objects with List<S> of custom objects for equality

I'm writing some UnitTests for a parser and I'm stuck at comparing two List<T> where T is a class of my own, that contains another List<S>.
My UnitTest compares two lists and fails. The code in the UnitTest looks like this:
CollectionAssert.AreEqual(list1, list2, "failed");
I've written a test scenario that should clarify my question:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ComparerTest
{
class Program
{
static void Main(string[] args)
{
List<SimplifiedClass> persons = new List<SimplifiedClass>()
{
new SimplifiedClass()
{
FooBar = "Foo1",
Persons = new List<Person>()
{
new Person(){ ValueA = "Hello", ValueB="Hello"},
new Person(){ ValueA = "Hello2", ValueB="Hello2"},
}
}
};
List<SimplifiedClass> otherPersons = new List<SimplifiedClass>()
{
new SimplifiedClass()
{
FooBar = "Foo1",
Persons = new List<Person>()
{
new Person(){ ValueA = "Hello2", ValueB="Hello2"},
new Person(){ ValueA = "Hello", ValueB="Hello"},
}
}
};
// The goal is to ignore the order of both lists and their sub-lists.. just check if both lists contain the exact items (in the same amount). Basically ignore the order
// This is how I try to compare in my UnitTest:
//CollectionAssert.AreEqual(persons, otherPersons, "failed");
}
}
public class SimplifiedClass
{
public String FooBar { get; set; }
public List<Person> Persons { get; set; }
public override bool Equals(object obj)
{
if (obj == null) { return false;}
PersonComparer personComparer = new PersonComparer();
SimplifiedClass obj2 = (SimplifiedClass)obj;
return this.FooBar == obj2.FooBar && Enumerable.SequenceEqual(this.Persons, obj2.Persons, personComparer); // I think here is my problem
}
public override int GetHashCode()
{
return this.FooBar.GetHashCode() * 117 + this.Persons.GetHashCode();
}
}
public class Person
{
public String ValueA { get; set; }
public String ValueB { get; set; }
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
Person obj2 = (Person)obj;
return this.ValueA == obj2.ValueA && this.ValueB == obj2.ValueB;
}
public override int GetHashCode()
{
if (!String.IsNullOrEmpty(this.ValueA))
{
//return this.ValueA.GetHashCode() ^ this.ValueB.GetHashCode();
return this.ValueA.GetHashCode() * 117 + this.ValueB.GetHashCode();
}
else
{
return this.ValueB.GetHashCode();
}
}
}
public class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
if (x != null)
{
return x.Equals(y);
}
else
{
return y == null;
}
}
public int GetHashCode(Person obj)
{
return obj.GetHashCode();
}
}
}
The question is strongly related to C# Compare Lists with custom object but ignore order, but I can't find the difference, other than I wrap a list into another object and use the UnitTest one level above.
I've tried to use an IEqualityComparer:
public class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person x, Person y)
{
if (x != null)
{
return x.Equals(y);
}
else
{
return y == null;
}
}
public int GetHashCode(Person obj)
{
return obj.GetHashCode();
}
}
Afterwards I've tried to implement the ''IComparable'' interface thats allows the objects to be ordered. (Basically like this: https://stackoverflow.com/a/4188041/225808)
However, I don't think my object can be brought into a natural order. Therefore I consider this a hack, if I come up with random ways to sort my class.
public class Person : IComparable<Person>
public int CompareTo(Person other)
{
if (this.GetHashCode() > other.GetHashCode()) return -1;
if (this.GetHashCode() == other.GetHashCode()) return 0;
return 1;
}
I hope I've made no mistakes while simplifying my problem. I think the main problems are:
How can I allow my custom objects to be comparable and define the equality in SimplifiedClass, that relies on the comparision of subclasses (e.g. Person in a list, like List<Person>). I assume Enumerable.SequenceEqual should be replaced with something else, but I don't know with what.
Is CollectionAssert.AreEqual the correct method in my UnitTest?
Equals on a List<T> will only check reference equality between the lists themselves, it does not attempt to look at the items in the list. And as you said you don't want to use SequenceEqual because you don't care about the ordering. In that case you should use CollectionAssert.AreEquivalent, it acts just like Enumerable.SequenceEqual however it does not care about the order of the two collections.
For a more general method that can be used in code it will be a little more complicated, here is a re-implemented version of what Microsoft is doing in their assert method.
public static class Helpers
{
public static bool IsEquivalent(this ICollection source, ICollection target)
{
//These 4 checks are just "shortcuts" so we may be able to return early with a result
// without having to do all the work of comparing every member.
if (source == null != (target == null))
return false; //If one is null and one is not, return false immediately.
if (object.ReferenceEquals((object)source, (object)target) || source == null)
return true; //If both point to the same reference or both are null (We validated that both are true or both are false last if statement) return true;
if (source.Count != target.Count)
return false; //If the counts are different return false;
if (source.Count == 0)
return true; //If the count is 0 there is nothing to compare, return true. (We validated both counts are the same last if statement).
int nullCount1;
int nullCount2;
//Count up the duplicates we see of each element.
Dictionary<object, int> elementCounts1 = GetElementCounts(source, out nullCount1);
Dictionary<object, int> elementCounts2 = GetElementCounts(target, out nullCount2);
//It checks the total number of null items in the collection.
if (nullCount2 != nullCount1)
{
//The count of nulls was different, return false.
return false;
}
else
{
//Go through each key and check that the duplicate count is the same for
// both dictionaries.
foreach (object key in elementCounts1.Keys)
{
int sourceCount;
int targetCount;
elementCounts1.TryGetValue(key, out sourceCount);
elementCounts2.TryGetValue(key, out targetCount);
if (sourceCount != targetCount)
{
//Count of duplicates for a element where different, return false.
return false;
}
}
//All elements matched, return true.
return true;
}
}
//Builds the dictionary out of the collection, this may be re-writeable to a ".GroupBy(" but I did not take the time to do it.
private static Dictionary<object, int> GetElementCounts(ICollection collection, out int nullCount)
{
Dictionary<object, int> dictionary = new Dictionary<object, int>();
nullCount = 0;
foreach (object key in (IEnumerable)collection)
{
if (key == null)
{
++nullCount;
}
else
{
int num;
dictionary.TryGetValue(key, out num);
++num;
dictionary[key] = num;
}
}
return dictionary;
}
}
What it does is it makes a dictionary out of the two collections, counting the duplicates and storing it as the value. It then compares the two dictionaries to make sure that the duplicate count matches for both sides. This lets you know that {1, 2, 2, 3} and {1, 2, 3, 3} are not equal where Enumerable.Execpt would tell you that they where.

How to get a Distinct result using LINQ and C# using method syntax [duplicate]

This question already has answers here:
How can I maintain type when using LINQ .Select in C#?
(4 answers)
Closed 9 years ago.
The following code still does not return a DISTINCT result set. The equivalent SQL I am trying to accomplish is SELECT DISTINCT LEFT(Fac_Name, 6) AS ID, LEFT(Fac_Name, 3) AS Fac_Name
public List<Facility> GetFacilities() {
var facilities = new List<Facility>();
facilities = _facilityRepository.GetAll().ToList();
var facReturnList =
facilities.Where(x => x.Fac_Name = "Something")
.OrderBy(x => x.Fac_Name).ToList();
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct().ToList();
return facReturnList2;
}
The problem you have is that you're creating distinct reference values (which will return different hashcodes), even if the properties inside each reference are equal, the actual references themselves are distinct.
// fac1 and fac2 are the same reference, fac3 is a different reference.
var fac1 = new Facility { ID = "0", Fac_Name = "Hello" };
var fac2 = fac1;
var fac3 = new Facility { ID = "0", Fac_Name = "Hello" };
var facs = new List<Facility>() { fac1, fac2, fac3 };
foreach (var fac in facs.Distinct())
Console.WriteLine("Id: {0} | Name: {1}", fac.ID, fac.Fac_Name);
// OUTPUT
// Id: 0 | Name: Hello (NOTE: This is the value of fac1/fac2)
// Id: 0 | Name: Hello (This is the value of fac3)
To solve your dilemma, you should either:
Override the Object.GetHashCode() and the Object.Equals(Object) methods. Note that Distinct() ultimately uses the GetHashCode() to determine if something is distinct, but Equals(Object) and GetHashCode() should be overridden together.
Guidelines for Overloading Equals() and Operator ==
public class Facility
{
public string ID { get; set; }
public string Fac_Name { get; set; }
// This is just a rough example.
public override bool Equals(Object obj)
{
var fac = obj as Facility;
if (fac == null) return false;
if (Object.ReferenceEquals(this, fac)) return true;
return (this.ID == fac.ID) && (this.Fac_Name == fac.Fac_Name);
}
public override int GetHashCode()
{
var hash = 13;
if (!String.IsNullOrEmpty(this.ID))
hash ^= ID.GetHashCode();
if (!String.IsNullOrEmpty(this.Fac_Name))
hash ^= Fac_Name.GetHashCode();
return hash;
}
}
Provide a custom IEqualityComparer<T>.
public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
public bool Equals(Facility x, Facility y)
{
return (x.ID == y.ID) && (x.Fac_Name == y.Fac_Name);
}
public int GetHashCode(Facility fac)
{
var hash = 13;
if (!String.IsNullOrEmpty(this.ID))
hash ^= ID.GetHashCode();
if (!String.IsNullOrEmpty(this.Fac_Name))
hash ^= Fac_Name.GetHashCode();
return hash;
}
}
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct(new FacilityEqualityComparer()).ToList();
Also, some other things to note:
You're naming does not follow guidelines. Don't use underscores in property names, and ID should be Id.
Whichever way you decide to go with, you should look into using String.Equals(...) and specify a StringComparison value. I just used == equality comparison on strings to keep the post short and readable.
So the problem is that the Enumerable.Distinct method uses the default equality comparer - which is comparing hash codes - so it will be a distinct list regardless of the properties values. Build an equality comparer for that type:
public class FacilityEqualityComparer : IEqualityComparer<Facility>
{
public bool Equals(Facility fac1, Facility fac2)
{
return fac1.ID.Equals(fac2.ID) && fac1.Fac_Name.Equals(fac2.Fac_Name);
}
public int GetHashCode(Facility fac)
{
string hCode = fac.ID + fac.Fac_Name;
return hCode.GetHashCode();
}
}
and then when you use it, call it like this:
var facReturnList2 =
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3) })
.Distinct(new FacilityEqualityComparer()).ToList();
return facReturnList2;
Distinct uses the default equality comparer to check for equality. This means it's looking for reference equality, which obviously won't be there in your case.
So you'll either need to use a custom IEqualityComparer (see the overload for Distinct(), or you can replicate the functionality of Distinct() with a GroupBy() and a First():
facReturnList.Select(x =>
new Facility { ID = x.Fac_Name.Substring(0, 6),
Fac_Name = x.Fac_Name.Substring(0, 3)
})
.GroupBy(x => new{x.ID, x.Fac_Name})
.Select(y => y.First())
.ToList();
You could also Override the Equals method in your Facility class:
public override bool Equals(System.Object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
Facility objAsFacility = obj as Facility;
return Equals(objAsFacility);
}
protected bool Equals(Facility other)
{
if (other.Fac_Name == this.Fac_Name)
return true;
else return false;
}
public override int GetHashCode()
{
return this.Fac_Name.GetHashCode();
//Or you might even want to this:
//return (this.ID + this.Fac_Name).GetHashCode();
}
I'd probably go with the overriding equality operator method.

Best way to compare two complex objects

I have two complex objects like Object1 and Object2. They have around 5 levels of child objects.
I need the fastest method to say if they are same or not.
How could this be done in C# 4.0?
Implement IEquatable<T> (typically in conjunction with overriding the inherited Object.Equals and Object.GetHashCode methods) on all your custom types. In the case of composite types, invoke the contained types’ Equals method within the containing types. For contained collections, use the SequenceEqual extension method, which internally calls IEquatable<T>.Equals or Object.Equals on each element. This approach will obviously require you to extend your types’ definitions, but its results are faster than any generic solutions involving serialization.
Edit: Here is a contrived example with three levels of nesting.
For value types, you can typically just call their Equals method. Even if the fields or properties were never explicitly assigned, they would still have a default value.
For reference types, you should first call ReferenceEquals, which checks for reference equality – this would serve as an efficiency boost when you happen to be referencing the same object. It would also handle cases where both references are null. If that check fails, confirm that your instance's field or property is not null (to avoid NullReferenceException) and call its Equals method. Since our members are properly typed, the IEquatable<T>.Equals method gets called directly, bypassing the overridden Object.Equals method (whose execution would be marginally slower due to the type cast).
When you override Object.Equals, you’re also expected to override Object.GetHashCode; I didn’t do so below for the sake of conciseness.
public class Person : IEquatable<Person>
{
public int Age { get; set; }
public string FirstName { get; set; }
public Address Address { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Person);
}
public bool Equals(Person other)
{
if (other == null)
return false;
return this.Age.Equals(other.Age) &&
(
object.ReferenceEquals(this.FirstName, other.FirstName) ||
this.FirstName != null &&
this.FirstName.Equals(other.FirstName)
) &&
(
object.ReferenceEquals(this.Address, other.Address) ||
this.Address != null &&
this.Address.Equals(other.Address)
);
}
}
public class Address : IEquatable<Address>
{
public int HouseNo { get; set; }
public string Street { get; set; }
public City City { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as Address);
}
public bool Equals(Address other)
{
if (other == null)
return false;
return this.HouseNo.Equals(other.HouseNo) &&
(
object.ReferenceEquals(this.Street, other.Street) ||
this.Street != null &&
this.Street.Equals(other.Street)
) &&
(
object.ReferenceEquals(this.City, other.City) ||
this.City != null &&
this.City.Equals(other.City)
);
}
}
public class City : IEquatable<City>
{
public string Name { get; set; }
public override bool Equals(object obj)
{
return this.Equals(obj as City);
}
public bool Equals(City other)
{
if (other == null)
return false;
return
object.ReferenceEquals(this.Name, other.Name) ||
this.Name != null &&
this.Name.Equals(other.Name);
}
}
Update: This answer was written several years ago. Since then, I've started to lean away from implementing IEquality<T> for mutable types for such scenarios. There are two notions of equality: identity and equivalence. At a memory representation level, these are popularly distinguished as “reference equality” and “value equality” (see Equality Comparisons). However, the same distinction can also apply at a domain level. Suppose that your Person class has a PersonId property, unique per distinct real-world person. Should two objects with the same PersonId but different Age values be considered equal or different? The answer above assumes that one is after equivalence. However, there are many usages of the IEquality<T> interface, such as collections, that assume that such implementations provide for identity. For example, if you're populating a HashSet<T>, you would typically expect a TryGetValue(T,T) call to return existing elements that share merely the identity of your argument, not necessarily equivalent elements whose contents are completely the same. This notion is enforced by the notes on GetHashCode:
In general, for mutable reference types, you should override GetHashCode() only if:
You can compute the hash code from fields that are not mutable; or
You can ensure that the hash code of a mutable object does not change while the object is contained in a collection that relies on its hash code.
Serialize both objects and compare the resulting strings
You can use extension method, recursion to resolve this problem:
public static bool DeepCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
//Compare two object's class, return false if they are difference
if (obj.GetType() != another.GetType()) return false;
var result = true;
//Get all properties of obj
//And compare each other
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
if (!objValue.Equals(anotherValue)) result = false;
}
return result;
}
public static bool CompareEx(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
//properties: int, double, DateTime, etc, not class
if (!obj.GetType().IsClass) return obj.Equals(another);
var result = true;
foreach (var property in obj.GetType().GetProperties())
{
var objValue = property.GetValue(obj);
var anotherValue = property.GetValue(another);
//Recursion
if (!objValue.DeepCompare(anotherValue)) result = false;
}
return result;
}
or compare by using Json (if object is very complex)
You can use Newtonsoft.Json:
public static bool JsonCompare(this object obj, object another)
{
if (ReferenceEquals(obj, another)) return true;
if ((obj == null) || (another == null)) return false;
if (obj.GetType() != another.GetType()) return false;
var objJson = JsonConvert.SerializeObject(obj);
var anotherJson = JsonConvert.SerializeObject(another);
return objJson == anotherJson;
}
If you don't want to implement IEquatable, you can always use Reflection to compare all the properties:
- if they're value type, just compare them
-if they are reference type, call the function recursively to compare its "inner" properties.
I'm not thinking about performace, but about simplicity. It depends, however on the exact design of your objects. It could get complicated depending on your objects shape (for example if there are cyclic dependencies between properties). There are, however, several solutions out there that you can use, like this one:
Compare .NET objects
Another option is to serialize the object as text, for example using JSON.NET, and comparing the serialization result. (JSON.NET can handle Cyclic dependencies between properties).
I don't know if by fastest you mean the fastest way to implement it or a code that runs fast. You should not optimize before knowing if you need to. Premature optimization is the root of all evil
Serialize both objects and compare the resulting strings by #JoelFan
So to do this, create a static class like so and use Extensions to extend ALL objects (so you can pass anytype of object, collection, etc into the method)
using System;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
public static class MySerializer
{
public static string Serialize(this object obj)
{
var serializer = new DataContractJsonSerializer(obj.GetType());
using (var ms = new MemoryStream())
{
serializer.WriteObject(ms, obj);
return Encoding.Default.GetString(ms.ToArray());
}
}
}
Once you reference this static class in any other file, you can do this:
Person p = new Person { Firstname = "Jason", LastName = "Argonauts" };
Person p2 = new Person { Firstname = "Jason", LastName = "Argonaut" };
//assuming you have already created a class person!
string personString = p.Serialize();
string person2String = p2.Serialize();
Now you can simply use .Equals to compare them.
I use this for checking if objects are in collections too. It works really well.
If you have a requirement where you want the class which is immutable. I mean that none of the properties can be modified once it's been created. In that case, C# 9 have a feature which is called a record.
You can easily compare records by values and types is they are equal.
public record Person
{
public string LastName { get; }
public string FirstName { get; }
public Person(string first, string last) => (FirstName, LastName) = (first, last);
}
var person1 = new Person("Bill", "Wagner");
var person2 = new Person("Bill", "Wagner");
Console.WriteLine(person1 == person2); // true
You can now use json.net. Just go on Nuget and install it.
And you can do something like this:
public bool Equals(SamplesItem sampleToCompare)
{
string myself = JsonConvert.SerializeObject(this);
string other = JsonConvert.SerializeObject(sampleToCompare);
return myself == other;
}
You could perhaps make a extension method for object if you wanted to get fancier. Please note this only compares the public properties. And if you wanted to ignore a public property when you do the comparison you could use the [JsonIgnore] attribute.
Serialize both objects, then calculate Hash Code, then compare.
I'll assume you are not referring to literally the same objects
Object1 == Object2
You might be thinking about doing a memory comparison between the two
memcmp(Object1, Object2, sizeof(Object.GetType())
But that's not even real code in c# :). Because all of your data is probably created on the heap, the memory is not contiguous and you can't just compare the equality of two objects in an agnostic manner. You're going to have to compare each value, one at a time, in a custom way.
Consider adding the IEquatable<T> interface to your class, and define a custom Equals method for your type. Then, in that method, manual test each value. Add IEquatable<T> again on enclosed types if you can and repeat the process.
class Foo : IEquatable<Foo>
{
public bool Equals(Foo other)
{
/* check all the values */
return false;
}
}
Based off a few answers already given here I decided to mostly back JoelFan's answer. I love extension methods and these have been working great for me when none of the other solutions would using them to compare my complex classes.
Extension Methods
using System.IO;
using System.Xml.Serialization;
static class ObjectHelpers
{
public static string SerializeObject<T>(this T toSerialize)
{
XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
using (StringWriter textWriter = new StringWriter())
{
xmlSerializer.Serialize(textWriter, toSerialize);
return textWriter.ToString();
}
}
public static bool EqualTo(this object obj, object toCompare)
{
if (obj.SerializeObject() == toCompare.SerializeObject())
return true;
else
return false;
}
public static bool IsBlank<T>(this T obj) where T: new()
{
T blank = new T();
T newObj = ((T)obj);
if (newObj.SerializeObject() == blank.SerializeObject())
return true;
else
return false;
}
}
Usage Examples
if (record.IsBlank())
throw new Exception("Record found is blank.");
if (record.EqualTo(new record()))
throw new Exception("Record found is blank.");
I would say that:
Object1.Equals(Object2)
would be what you're looking for. That's if you're looking to see if the objects are the same, which is what you seem to be asking.
If you want to check to see if all the child objects are the same, run them through a loop with the Equals() method.
I found this below function for comparing objects.
static bool Compare<T>(T Object1, T object2)
{
//Get the type of the object
Type type = typeof(T);
//return false if any of the object is false
if (object.Equals(Object1, default(T)) || object.Equals(object2, default(T)))
return false;
//Loop through each properties inside class and get values for the property from both the objects and compare
foreach (System.Reflection.PropertyInfo property in type.GetProperties())
{
if (property.Name != "ExtensionData")
{
string Object1Value = string.Empty;
string Object2Value = string.Empty;
if (type.GetProperty(property.Name).GetValue(Object1, null) != null)
Object1Value = type.GetProperty(property.Name).GetValue(Object1, null).ToString();
if (type.GetProperty(property.Name).GetValue(object2, null) != null)
Object2Value = type.GetProperty(property.Name).GetValue(object2, null).ToString();
if (Object1Value.Trim() != Object2Value.Trim())
{
return false;
}
}
}
return true;
}
I am using it and it is working fine for me.
Thanks to the example of Jonathan. I expanded it for all cases (arrays, lists, dictionaries, primitive types).
This is a comparison without serialization and does not require the implementation of any interfaces for compared objects.
/// <summary>Returns description of difference or empty value if equal</summary>
public static string Compare(object obj1, object obj2, string path = "")
{
string path1 = string.IsNullOrEmpty(path) ? "" : path + ": ";
if (obj1 == null && obj2 != null)
return path1 + "null != not null";
else if (obj2 == null && obj1 != null)
return path1 + "not null != null";
else if (obj1 == null && obj2 == null)
return null;
if (!obj1.GetType().Equals(obj2.GetType()))
return "different types: " + obj1.GetType() + " and " + obj2.GetType();
Type type = obj1.GetType();
if (path == "")
path = type.Name;
if (type.IsPrimitive || typeof(string).Equals(type))
{
if (!obj1.Equals(obj2))
return path1 + "'" + obj1 + "' != '" + obj2 + "'";
return null;
}
if (type.IsArray)
{
Array first = obj1 as Array;
Array second = obj2 as Array;
if (first.Length != second.Length)
return path1 + "array size differs (" + first.Length + " vs " + second.Length + ")";
var en = first.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
string res = Compare(en.Current, second.GetValue(i), path);
if (res != null)
return res + " (Index " + i + ")";
i++;
}
}
else if (typeof(System.Collections.IEnumerable).IsAssignableFrom(type))
{
System.Collections.IEnumerable first = obj1 as System.Collections.IEnumerable;
System.Collections.IEnumerable second = obj2 as System.Collections.IEnumerable;
var en = first.GetEnumerator();
var en2 = second.GetEnumerator();
int i = 0;
while (en.MoveNext())
{
if (!en2.MoveNext())
return path + ": enumerable size differs";
string res = Compare(en.Current, en2.Current, path);
if (res != null)
return res + " (Index " + i + ")";
i++;
}
}
else
{
foreach (PropertyInfo pi in type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
try
{
var val = pi.GetValue(obj1);
var tval = pi.GetValue(obj2);
if (path.EndsWith("." + pi.Name))
return null;
var pathNew = (path.Length == 0 ? "" : path + ".") + pi.Name;
string res = Compare(val, tval, pathNew);
if (res != null)
return res;
}
catch (TargetParameterCountException)
{
//index property
}
}
foreach (FieldInfo fi in type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public))
{
var val = fi.GetValue(obj1);
var tval = fi.GetValue(obj2);
if (path.EndsWith("." + fi.Name))
return null;
var pathNew = (path.Length == 0 ? "" : path + ".") + fi.Name;
string res = Compare(val, tval, pathNew);
if (res != null)
return res;
}
}
return null;
}
For easy copying of the code created repository
public class GetObjectsComparison
{
public object FirstObject, SecondObject;
public BindingFlags BindingFlagsConditions= BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static;
}
public struct SetObjectsComparison
{
public FieldInfo SecondObjectFieldInfo;
public dynamic FirstObjectFieldInfoValue, SecondObjectFieldInfoValue;
public bool ErrorFound;
public GetObjectsComparison GetObjectsComparison;
}
private static bool ObjectsComparison(GetObjectsComparison GetObjectsComparison)
{
GetObjectsComparison FunctionGet = GetObjectsComparison;
SetObjectsComparison FunctionSet = new SetObjectsComparison();
if (FunctionSet.ErrorFound==false)
foreach (FieldInfo FirstObjectFieldInfo in FunctionGet.FirstObject.GetType().GetFields(FunctionGet.BindingFlagsConditions))
{
FunctionSet.SecondObjectFieldInfo =
FunctionGet.SecondObject.GetType().GetField(FirstObjectFieldInfo.Name, FunctionGet.BindingFlagsConditions);
FunctionSet.FirstObjectFieldInfoValue = FirstObjectFieldInfo.GetValue(FunctionGet.FirstObject);
FunctionSet.SecondObjectFieldInfoValue = FunctionSet.SecondObjectFieldInfo.GetValue(FunctionGet.SecondObject);
if (FirstObjectFieldInfo.FieldType.IsNested)
{
FunctionSet.GetObjectsComparison =
new GetObjectsComparison()
{
FirstObject = FunctionSet.FirstObjectFieldInfoValue
,
SecondObject = FunctionSet.SecondObjectFieldInfoValue
};
if (!ObjectsComparison(FunctionSet.GetObjectsComparison))
{
FunctionSet.ErrorFound = true;
break;
}
}
else if (FunctionSet.FirstObjectFieldInfoValue != FunctionSet.SecondObjectFieldInfoValue)
{
FunctionSet.ErrorFound = true;
break;
}
}
return !FunctionSet.ErrorFound;
}
Generic Extension Method
public static class GenericExtensions
{
public static bool DeepCompare<T>(this T objA, T objB)
{
if (typeof(T).IsValueType)
return objA.Equals(objB);
if (ReferenceEquals(objA, objB))
return true;
if ((objA == null) || (objB == null))
return false;
if (typeof(T) is IEnumerable)
{
var enumerableA = (IEnumerable<T>) objA;
var enumerableB = (IEnumerable<T>) objB;
if (enumerableA.Count() != enumerableB.Count())
return false;
using (var enumeratorA = enumerableA.GetEnumerator())
using (var enumeratorB = enumerableB.GetEnumerator())
{
while (true)
{
bool moveNextA = enumeratorA.MoveNext();
bool moveNextB = enumeratorB.MoveNext();
if (!moveNextA || !moveNextB)
break;
var currentA = enumeratorA.Current;
var currentB = enumeratorB.Current;
if (!currentA.DeepCompare<T>(currentB))
return false;
}
return true;
}
}
foreach (var property in objA.GetType().GetProperties())
{
var valueA = property.GetValue(objA);
var valueB = property.GetValue(objB);
if (!valueA.DeepCompare(valueB))
return false;
}
return true;
}
}
One way to do this would be to override Equals() on each type involved. For example, your top level object would override Equals() to call the Equals() method of all 5 child objects. Those objects should all override Equals() as well, assuming they are custom objects, and so on until the entire hierarchy could be compared by just performing an equality check on the top level objects.
Use IEquatable<T> Interface which has a method Equals.
To return each property updated:
public IEnumerable<string> GetPropsUpdated(T oldModel, T newModel)
{
var diff = new List<string>();
foreach (var prop in oldModel.GetType().GetProperties())
{
var oldValue = prop.GetValue(oldModel);
var newValue = prop.GetValue(newModel);
if (oldValue == null && newValue == null)
continue;
if (oldValue == null && newValue != null
|| oldValue != null && newValue == null)
{
diff.Add(prop.Name);
continue;
}
var oldPropHashed = oldValue.GetHashCode();
var newPropHashed = newValue.GetHashCode();
if (!oldPropHashed.Equals(newPropHashed))
diff.Add(prop.Name);
}
return diff;
}

Categories

Resources