Extension method to compare all fields including IEnumerable - c#

I am trying to write an extension method that compares objects based on their fields.
I have this:
public static class MyExtensions
{
public static bool FieldsEquals(this object o, object other)
{
if (ReferenceEquals(o, other))
return true;
if (o == null || other == null || o.GetType() != other.GetType())
return false;
foreach (var f in o.GetType().GetFields())
{
// is this a correct test ???
bool isEnumerable = f.FieldType != typeof(string) &&
typeof(IEnumerable).IsAssignableFrom(f.FieldType);
if (!isEnumerable)
{
if (!f.GetValue(o).Equals(f.GetValue(other)))
return false;
}
else
{
// convert both to IEnumerable and check if equal
}
}
return true;
}
}
I am struggling with the case of the field being a collection; I need to detect that case and then check the collections are the same (same number of elements and f.GetValue(o)[i] == f.GetValue(other)[i].
Any help?

Okay, like others already mentionend. There are a lot of edge cases..
I would recommend to use recursion for this kind of problem.
This method should also check arrays or lists that contain objects:
public static bool FieldsEquals(this object o1, object o2)
{
if (ReferenceEquals(o1, o2))
return true;
if (o1 == null || o2 == null || o1.GetType() != o2.GetType())
return false;
if (o1 is IEnumerable enumerable1 && o2 is IEnumerable enumerable2)
{
var enumerator1 = enumerable1.GetEnumerator();
var enumerator2 = enumerable2.GetEnumerator();
while(enumerator1.MoveNext())
{
if (!enumerator2.MoveNext())
{
return false;
}
if (!enumerator1.Current.FieldsEquals(enumerator2.Current))
{
return false;
}
}
}
else
{
foreach (var f in o1.GetType().GetFields())
{
var val1 = f.GetValue(o1);
var val2 = f.GetValue(o2);
if (val1 == null || val2 == null) continue;
if (val1 is IEnumerable e1 && val2 is IEnumerable e2)
{
if (!e1.FieldsEquals(e2))
{
return false;
}
}
else
{
if (!val1.Equals(val2))
{
return false;
}
}
}
}
return true;
}

To be honest, there are a lot of problems here. What if the types are basic types (like int) or Structs (datetime,etc). What if the enumerable fields contain classes not basic types? or the properties are classes?
See this question for some guidelines on deep equality: Compare the content of two objects for equality
All that said, here is my crack at the code you mentioned
public static bool FieldsEquals(this object o, object other)
{
if (ReferenceEquals(o, other)) return true;
if (o == null || other == null || o.GetType() != other.GetType()) return false;
foreach (var f in o.GetType().GetFields())
{
bool isEnumerable = f.GetValue(o).GetType().IsAssignableFrom(typeof(System.Collections.IEnumerable));// but is not a string
if (!isEnumerable)
{
if (!f.GetValue(o).Equals(f.GetValue(other))) return false;
}
else
{
var first = ((System.Collections.IEnumerable)f.GetValue(o)).Cast<object>().ToArray();
var second = ((System.Collections.IEnumerable)f.GetValue(other)).Cast<object>().ToArray();
if (first.Length != second.Length)
return false;
for (int i = 0; i < first.Length; i++)
{
if (first[i] != second[i]) //assumes they are basic types, which implement equality checking. If they are classes, you may need to recursively call this method
return false;
}
}
}
return true;
}

Related

Is there any generic TypeConvertor with good performance?

I am using the following generic method for type conversion at runtime. But it takes time and affects the performance a bit.
For 381 values conversion it takes 9922.71 milliseconds.
Is there any best way to improve this?
public static void test()
{
Stopwatch watch = new Stopwatch();
watch.Start();
for (int i = 0; i < 200; i++)
{
var xi = Common.CoerceValue(typeof(Guid), typeof(string), null, Guid.NewGuid().ToString());
}
watch.Stop();
double timetaken = watch.Elapsed.TotalMilliseconds;
}
public static object CoerceValue(Type desiredType, Type valueType, object oldValue, object value)
{
if (desiredType.Equals(valueType))
{
// types match, just return value
return value;
}
else
{
if (desiredType.IsGenericType)
{
if (desiredType.GetGenericTypeDefinition() == typeof(Nullable<>))
{
if (value == null)
return null;
else if (valueType.Equals(typeof(string)) && System.Convert.ToString(value) == string.Empty)
return null;
}
desiredType = GetPropertyType(desiredType);
}
if (desiredType.IsEnum && (valueType.Equals(typeof(string)) || Enum.GetUnderlyingType(desiredType).Equals(valueType)))
return System.Enum.Parse(desiredType, value.ToString());
if ((desiredType.IsPrimitive || desiredType.Equals(typeof(decimal))) &&
valueType.Equals(typeof(string)) && string.IsNullOrEmpty((string)value))
value = 0;
try
{
if (desiredType.Equals(typeof(string)) && value != null)
{
return value.ToString();
}
else if (desiredType.Equals(typeof(Boolean)) && valueType.Equals(typeof(string)))
{
return "1" == Convert.ToString(value) || "TRUE" == Convert.ToString(value).ToUpper1();
}
else
{
if (desiredType.Equals(typeof(Guid)) && DBUtility.DBType == Core.Enums.DataBaseType.ORACLE)
{
TypeConverter cnv = TypeDescriptor.GetConverter(desiredType);
return cnv.ConvertFrom(value);
}
else
return Convert.ChangeType(value, desiredType);
}
}
catch
{
TypeConverter cnv = TypeDescriptor.GetConverter(desiredType);
if (cnv != null && cnv.CanConvertFrom(valueType))
return cnv.ConvertFrom(value);
else
throw;
}
}
}
public static Type GetPropertyType(Type propertyType)
{
Type type = propertyType;
if (type.IsGenericType &&
(type.GetGenericTypeDefinition() == typeof(Nullable<>)))
return Nullable.GetUnderlyingType(type);
return type;
}
There is bug in the code which threw conversion error for guid (string) to guid type.
return Convert.ChangeType(value, desiredType);
so while converting 121 guids got error and resolved in the catch block. after fix, now it takes few milliseconds.

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

How to determine if a type is of type HashSet and how to cast it?

I have someone on GitHub asking for the ability to compare HashSets for my project on GitHub: https://github.com/GregFinzer/Compare-Net-Objects/. I need to be able to determine if a type is a hash set and then get the enumerator. I am not sure what to cast it to. Here is what I have for an IList:
private bool IsIList(Type type)
{
return (typeof(IList).IsAssignableFrom(type));
}
private void CompareIList(object object1, object object2, string breadCrumb)
{
IList ilist1 = object1 as IList;
IList ilist2 = object2 as IList;
if (ilist1 == null) //This should never happen, null check happens one level up
throw new ArgumentNullException("object1");
if (ilist2 == null) //This should never happen, null check happens one level up
throw new ArgumentNullException("object2");
try
{
_parents.Add(object1);
_parents.Add(object2);
//Objects must be the same length
if (ilist1.Count != ilist2.Count)
{
Differences.Add(string.Format("object1{0}.Count != object2{0}.Count ({1},{2})", breadCrumb,
ilist1.Count, ilist2.Count));
if (Differences.Count >= MaxDifferences)
return;
}
IEnumerator enumerator1 = ilist1.GetEnumerator();
IEnumerator enumerator2 = ilist2.GetEnumerator();
int count = 0;
while (enumerator1.MoveNext() && enumerator2.MoveNext())
{
string currentBreadCrumb = AddBreadCrumb(breadCrumb, string.Empty, string.Empty, count);
Compare(enumerator1.Current, enumerator2.Current, currentBreadCrumb);
if (Differences.Count >= MaxDifferences)
return;
count++;
}
}
finally
{
_parents.Remove(object1);
_parents.Remove(object2);
}
}
I believe it is enough works directly with the ISet<T>, the ICollection<T> or the IEnumerable<T> generic interfaces instead of the HashSet<T>. You can detect these types using the following approach:
// ...
Type t = typeof(HashSet<int>);
bool test1 = GenericClassifier.IsICollection(t); // true
bool test2 = GenericClassifier.IsIEnumerable(t); // true
bool test3 = GenericClassifier.IsISet(t); // true
}
//
public static class GenericClassifier {
public static bool IsICollection(Type type) {
return Array.Exists(type.GetInterfaces(), IsGenericCollectionType);
}
public static bool IsIEnumerable(Type type) {
return Array.Exists(type.GetInterfaces(), IsGenericEnumerableType);
}
public static bool IsISet(Type type) {
return Array.Exists(type.GetInterfaces(), IsGenericSetType);
}
static bool IsGenericCollectionType(Type type) {
return type.IsGenericType && (typeof(ICollection<>) == type.GetGenericTypeDefinition());
}
static bool IsGenericEnumerableType(Type type) {
return type.IsGenericType && (typeof(IEnumerable<>) == type.GetGenericTypeDefinition());
}
static bool IsGenericSetType(Type type) {
return type.IsGenericType && (typeof(ISet<>) == type.GetGenericTypeDefinition());
}
}
You need to loop over GetInterfaces() and check whether it implements an interface where IsGenericType is true and GetGenericTypeDefinition() == typeof(ISet<>)
Accepted answer does not distinguish from Dictionary type and possibly other subclasses of ICollection and IEnumerable. This works better:
Type t1 = typeof(HashSet<int>);
bool test1 = t1.IsGenericType &&
t1.GetGenericTypeDefinition() == typeof(HashSet<>); // true
Type t2 = typeof(Dictionary<int, string>);
bool test2 = t2.IsGenericType &&
t2.GetGenericTypeDefinition() == typeof(HashSet<>); // false
Type t3 = typeof(int);
bool test3 = t3.IsGenericType &&
t3.GetGenericTypeDefinition() == typeof(HashSet<>); // false
This is built in to HashSets... Use the method SymmetricExceptWith. There are other built in comparisons as well. See: http://msdn.microsoft.com/en-us/library/bb336848.aspx

Check two object, of unknown type, for equality, comparing all their fields

I need to define a method to compare two different objects of a same type. The type of objects is not specific. The objects may be a DLL type, so I can't override Equals method. I have to do this by reflection. This code works if all the members of objects are of primitive type. But it doesn't work when an object has a field that isn't primitive. How can I do it by reflection?
public bool Equals(object obj1, object obj2)
{
List<FieldInfo> fieldInfos = obj1.GetType().GetFields().ToList();
return (fieldInfos.Select(fieldInfo => new {fieldInfo, type = fieldInfo.GetType()})
.Where(#t => #t.type.IsPrimitive || #t.type == typeof(string) || #t.type == typeof(Decimal))
.Select(#t => #t.fieldInfo)).All(fieldInfo => fieldInfo.GetValue(obj1).Equals(fieldInfo.GetValue(obj2)));
}
I have recently been told about this lib that will do exactly what you are wanting
http://comparenetobjects.codeplex.com/releases/view/47978
I want the utility function to compare any 2 objects. All of the type I want to cover is
Primitive Type
Any class that Implement IEnumerable (Like Dict or List)
Any Class
so I use generic and reflection to do so. I code it like this.
public static bool CompareObjects<T>(T expectInput, T actualInput)
{
// If T is primitive type.
if (typeof(T).IsPrimitive)
{
if (expectInput.Equals(actualInput))
{
return true;
}
return false;
}
if (expectInput is IEquatable<T>)
{
if (expectInput.Equals(actualInput))
{
return true;
}
return false;
}
if (expectInput is IComparable)
{
if (((IComparable)expectInput).CompareTo(actualInput) == 0)
{
return true;
}
return false;
}
// If T is implement IEnumerable.
if (expectInput is IEnumerable)
{
var expectEnumerator = ((IEnumerable)expectInput).GetEnumerator();
var actualEnumerator = ((IEnumerable)actualInput).GetEnumerator();
var canGetExpectMember = expectEnumerator.MoveNext();
var canGetActualMember = actualEnumerator.MoveNext();
while (canGetExpectMember && canGetActualMember && true)
{
var currentType = expectEnumerator.Current.GetType();
object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(currentType).Invoke(null, new object[] { expectEnumerator.Current, actualEnumerator.Current });
if ((bool)isEqual == false)
{
return false;
}
canGetExpectMember = expectEnumerator.MoveNext();
canGetActualMember = actualEnumerator.MoveNext();
}
if (canGetExpectMember != canGetActualMember)
{
return false;
}
return true;
}
// If T is class.
var properties = typeof(T).GetProperties();
foreach (var property in properties)
{
var expectValue = typeof(T).GetProperty(property.Name).GetValue(expectInput);
var actualValue = typeof(T).GetProperty(property.Name).GetValue(actualInput);
if (expectValue == null || actualValue == null)
{
if (expectValue == null && actualValue == null)
{
continue;
}
return false;
}
object isEqual = typeof(Utils).GetMethod("CompareObjects").MakeGenericMethod(property.PropertyType).Invoke(null, new object[] { expectValue, actualValue });
if ((bool)isEqual == false)
{
return false;
}
}
return true;
}

Comparing two classes in LINQ - getting 'mismatches'

I have the following class:
public class DocumentCompare
{
public string Customer;
public string Filename;
public string Reference;
public DateTime? Date;
public override bool Equals(object obj)
{
if (obj == null)
return false;
DocumentCompare doc = obj as DocumentCompare;
if ((Object)doc == null)
return false;
return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
}
public bool Equals(DocumentCompare doc)
{
if ((object)doc == null)
return false;
return (doc.Customer == Customer) && (doc.Date == Date) && (doc.Filename == Filename) && (doc.Reference == Reference);
}
public override int GetHashCode()
{
return string.Format("{0}_{1}_{2}_{3}",Customer,Filename,Reference,(Date == null ? "" : Date.Value.ToString())).GetHashCode();
}
}
I will be retrieving 2 lists of this class - what I want to do is to compare the two, and get ones that don't exist in both. So if an item exists in x list but not in y, I want to perform an action for the items in this list. If an item exists in y list but not in x, I want to do a different action.
How would I do this? Using LINQ I guess!
EDIT: Performance is not much of an issue - this will only be run once
It sounds like you just want Except:
foreach (var newItem in firstList.Except(secondList))
{
...
}
As an aside:
That's not a terribly nice way of generating a hash code - search for other questions here.
Delegate from Equals(object) to Equals(DocumentCompare) to avoid repetitive logic
Mutable types aren't great candidates for equality comparisons (in particular, one you've used a value as a key in a dictionary, if you change the equality-sensitive components you won't be able to find the key again)
Even if you do want it to be mutable, properties are better for encapsulation than public fields
I would either seal the type or check whether the two objects are exactly the same type, as otherwise you could end up with asymmetric equality
here is the code:
var elementsMissingFromFirstList = firstList.Except(secondList).ToList();
var elementsMissingInSecondList = secondList.Except(firstList).ToList();
now you can perform your actions on these missing elements :)
You can use this method to compare objects of two different Lists. exmp: List and List x and y = DocumentCompare,
public static bool EqualsObject<T>(this T t1, T t2) where T : class
{
var p1 = t1.GetType().Fields();
var p2 = t2.GetType().Fields();
for (int j = 0; j < p1.Length; j++)
{
var x = p1[j].GetValue(t1, null);
var y = p2[j].GetValue(t2, null);
if (x == null && y == null)
continue;
if (x != null && y == null)
return false;
if (x == null)
return false;
if (!x.Equals(y))
{
return false;
}
}
return true;
}
This method will show the difference between these two lists.
public static List<T> DifferentObjects<T>(List<T> t, List<T> t2) where T : class
{
var diff = new List<T>();
if (t != null && t2 != null)
{
foreach (T t1 in t)
{
var state = false;
foreach (T t3 in t2.Where(t3 => EqualsObject(t1,t3)))
{
state = true;
}
if (!state)
{
diff.Add(t1);
}
}
}
return diff;
}
you can use code this way
var t = new List<DocumentCompare>();
var t2 = new List<DocumentCompare>();
t.Add(new DocumentCompare{Customer = "x"});
t.Add(new DocumentCompare{Customer = "y"});
t.Add(new DocumentCompare{Customer = "z"});
t2.Add(new DocumentCompare { Customer = "t" });
t2.Add(new DocumentCompare { Customer = "y" });
t2.Add(new DocumentCompare { Customer = "z" });
var list = DifferentObjects(t, t2);
var list2 = DifferentObjects(t2, t);
you used fields (Customer,FileName etc..) in your class, so that GetType().Fields(); is used in EqualsObject method. if you use property , you should use GetType().Properties(); in EqualsObject method.

Categories

Resources