How to Quickly Check If Two Data Transfer Objects Have Equal Properties in C#

How to quickly check if two data transfer objects have equal properties in C#?

How about some reflection, perhaps using Expression.Compile() for performance? (note the static ctor here ensures we only compile it once per T):

using System;
using System.Linq.Expressions;

public class Report {
public int Id { get; set; }
public int ProjectId { get; set; }
static void Main() {
Report a = new Report { Id = 1, ProjectId = 13 },
b = new Report { Id = 1, ProjectId = 13 },
c = new Report { Id = 1, ProjectId = 12 };
Console.WriteLine(PropertyCompare.Equal(a, b));
Console.WriteLine(PropertyCompare.Equal(a, c));
}
}
static class PropertyCompare {
public static bool Equal<T>(T x, T y) {
return Cache<T>.Compare(x, y);
}
static class Cache<T> {
internal static readonly Func<T, T, bool> Compare;
static Cache() {
var props = typeof(T).GetProperties();
if (props.Length == 0) {
Compare = delegate { return true; };
return;
}
var x = Expression.Parameter(typeof(T), "x");
var y = Expression.Parameter(typeof(T), "y");

Expression body = null;
for (int i = 0; i < props.Length; i++) {
var propEqual = Expression.Equal(
Expression.Property(x, props[i]),
Expression.Property(y, props[i]));
if (body == null) {
body = propEqual;
} else {
body = Expression.AndAlso(body, propEqual);
}
}
Compare = Expression.Lambda<Func<T, T, bool>>(body, x, y)
.Compile();
}
}
}

Edit: updated to handle fields too:

static class MemberCompare
{
public static bool Equal<T>(T x, T y)
{
return Cache<T>.Compare(x, y);
}
static class Cache<T>
{
internal static readonly Func<T, T, bool> Compare;
static Cache()
{
var members = typeof(T).GetProperties(
BindingFlags.Instance | BindingFlags.Public)
.Cast<MemberInfo>().Concat(typeof(T).GetFields(
BindingFlags.Instance | BindingFlags.Public)
.Cast<MemberInfo>());
var x = Expression.Parameter(typeof(T), "x");
var y = Expression.Parameter(typeof(T), "y");

Expression body = null;
foreach(var member in members)
{
Expression memberEqual;
switch (member.MemberType)
{
case MemberTypes.Field:
memberEqual = Expression.Equal(
Expression.Field(x, (FieldInfo)member),
Expression.Field(y, (FieldInfo)member));
break;
case MemberTypes.Property:
memberEqual = Expression.Equal(
Expression.Property(x, (PropertyInfo)member),
Expression.Property(y, (PropertyInfo)member));
break;
default:
throw new NotSupportedException(
member.MemberType.ToString());
}
if (body == null)
{
body = memberEqual;
}
else
{
body = Expression.AndAlso(body, memberEqual);
}
}
if (body == null)
{
Compare = delegate { return true; };
}
else
{
Compare = Expression.Lambda<Func<T, T, bool>>(body, x, y)
.Compile();
}
}
}
}

Comparing object properties in c#

I was looking for a snippet of code that would do something similar to help with writing unit test. Here is what I ended up using.

public static bool PublicInstancePropertiesEqual<T>(T self, T to, params string[] ignore) where T : class 
{
if (self != null && to != null)
{
Type type = typeof(T);
List<string> ignoreList = new List<string>(ignore);
foreach (System.Reflection.PropertyInfo pi in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
{
if (!ignoreList.Contains(pi.Name))
{
object selfValue = type.GetProperty(pi.Name).GetValue(self, null);
object toValue = type.GetProperty(pi.Name).GetValue(to, null);

if (selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue)))
{
return false;
}
}
}
return true;
}
return self == to;
}

EDIT:

Same code as above but uses LINQ and Extension methods :

public static bool PublicInstancePropertiesEqual<T>(this T self, T to, params string[] ignore) where T : class
{
if (self != null && to != null)
{
var type = typeof(T);
var ignoreList = new List<string>(ignore);
var unequalProperties =
from pi in type.GetProperties(BindingFlags.Public | BindingFlags.Instance)
where !ignoreList.Contains(pi.Name) && pi.GetUnderlyingType().IsSimpleType() && pi.GetIndexParameters().Length == 0
let selfValue = type.GetProperty(pi.Name).GetValue(self, null)
let toValue = type.GetProperty(pi.Name).GetValue(to, null)
where selfValue != toValue && (selfValue == null || !selfValue.Equals(toValue))
select selfValue;
return !unequalProperties.Any();
}
return self == to;
}

public static class TypeExtensions
{
/// <summary>
/// Determine whether a type is simple (String, Decimal, DateTime, etc)
/// or complex (i.e. custom class with public properties and methods).
/// </summary>
/// <see cref="http://stackoverflow.com/questions/2442534/how-to-test-if-type-is-primitive"/>
public static bool IsSimpleType(
this Type type)
{
return
type.IsValueType ||
type.IsPrimitive ||
new[]
{
typeof(String),
typeof(Decimal),
typeof(DateTime),
typeof(DateTimeOffset),
typeof(TimeSpan),
typeof(Guid)
}.Contains(type) ||
(Convert.GetTypeCode(type) != TypeCode.Object);
}

public static Type GetUnderlyingType(this MemberInfo member)
{
switch (member.MemberType)
{
case MemberTypes.Event:
return ((EventInfo)member).EventHandlerType;
case MemberTypes.Field:
return ((FieldInfo)member).FieldType;
case MemberTypes.Method:
return ((MethodInfo)member).ReturnType;
case MemberTypes.Property:
return ((PropertyInfo)member).PropertyType;
default:
throw new ArgumentException
(
"Input MemberInfo must be if type EventInfo, FieldInfo, MethodInfo, or PropertyInfo"
);
}
}
}

How do I check if two Objects are equal in terms of their properties only without breaking the existing Object.Equals()?

Have you tried implementing your own IEqualityComparer? You can pass this to an .Equals() overload to define your own custom equality logic, as in

User A = User B even if they are distinct instances, if properties x, y, z are the same.

See this:
MSDN

Edit: I should have written you can instantiate your EqualityComparer and pass two instances to its Equals() method and get a bool. Basic console app... will show true, false, false. Thing is trivial, has the two properties shown.

var comparer = new ThingEqualityComparer();

Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, new Thing() { Id = 1, Name = "1" }));
Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, new Thing() { Id = 2, Name = "2" }));
Console.WriteLine(comparer.Equals(new Thing() { Id = 1, Name = "1" }, null));

class ThingEqualityComparer : IEqualityComparer<Thing>
{
public bool Equals(Thing x, Thing y)
{
if (x == null || y == null)
return false;

return (x.Id == y.Id && x.Name == y.Name);
}

public int GetHashCode(Thing obj)
{
return obj.GetHashCode();
}
}

how to compare values of two reference type nested and dynamic objects


use json

Convert each object into a json string, with all properties/fields sorted by name, then compare two strings. this is slow, but it works.

use reflection

Using reflection methods, compare each property/field one by one. Actually the json library do the same job. Doing the comparison yourself will save the time converting to string, but you have to dive into the nested types.

use some code generator, e.g. protobuf

If the datatype is just POCO type, maybe protobuf is a good choice. It introduces a lot advantages:

  • build-in comparison
  • json serialization and deserialization
  • very fast binary serialization and deserialization
  • cross-platform and cross language, integrated well with grpc inter-process communication
  • version compatibility, when new fields added, old data on disk can still be read by app.

Compare the content of two objects for equality


Is there a generic way to compare the content of the two objects?

Well yes, but generally that's known as the IComparable interface.

If you could descend from the class and create a child that implemented IComparable, that might be ideal.

Compare two object from the same class with tons of fields

Two ideas:

  1. Use reflection (it is available in C#) runtime and loop over the fields of the clas comparing them. If you want to be able to exclude certain fields you could do that by creating an attribute class and mark the fields you don't want to compare with that attribute.

  2. Use reflection to loop over the fields in the same way and generate the required comparison code. This way you will have "real" code but won't have to write and maintain it yourself. Attributes can be used to fine-tune the comparison code generated.

Is there an effective way to determine whether .Equals on two different but equal instances will return true?

You could do something based on this answer, noting that this compares the public properties, not the fields, and that Equals could do anything crazy it wants. It wouldn't be hard to change it to use fields instead, but... to be honest, I'm not sure what the driver is here. I'd just write the Equals(object) and Equals(MyComplexType) and use EqualityComparer<T>.Default.Equals(x,y) (which handles IEquatable<T>, nulls, Nullable<T>, etc - using object.Equals(x,y) as the fallback strategy).

For something that I think meets your updated need:

public static bool AreEqual<T>(T x, T y) {
if(ReferenceEquals(x,y)) return true;
if(x==null || y == null) return false;
IEquatable<T> eq = x as IEquatable<T>;
if(eq == null) return PropertyCompare.Equal(x,y);
return eq.Equals(y);
}


Related Topics



Leave a reply



Submit