Search code examples
c#.netexpression-treesdynamic-method

Comparing all properties of an object using expression trees


I'm trying to write a simple generator that uses an expression tree to dynamically generate a method that compares all properties of an instance of a type to the properties of another instance of that type. This works fine for most properties, like int an string, but fails for DateTime? (and presumably other nullable value types).

The method:

static Delegate GenerateComparer(Type type)
{
  var left = Expression.Parameter(type, "left");
  var right = Expression.Parameter(type, "right");

  Expression result = null;

  foreach (var p in type.GetProperties())
  {
    var leftProperty = Expression.Property(left, p.Name);
    var rightProperty = Expression.Property(right, p.Name);

    var equals = p.PropertyType.GetMethod("Equals", new[] { p.PropertyType });

    var callEqualsOnLeft = Expression.Call(leftProperty, equals, rightProperty);

    result = result != null ? (Expression)Expression.And(result, callEqualsOnLeft) : (Expression)callEqualsOnLeft;
  }

  var method = Expression.Lambda(result, left, right).Compile();

  return method;

}

On a DateTime? property it fails with:

Expression of type 'System.Nullable`1[System.DateTime]' cannot be used for parameter of type 'System.Object' of method 'Boolean Equals(System.Object)'

OK, so it finds an overload of Equals that expects object. So why can't I pass a DateTime? into that, as it's convertible to object? If I look at Nullable<T>, it indeed has an override of Equals(object o).

PS: I realize that this isn't a proper generator yet as it can't deal with null values, but I'll get to that :)

UPDATE: Iraklis' answer did work for this particular problem, but in the end I went for a much simpler approach that I think suffices: just use Expression.Equal. I think that covers 99% of my cases (not sure if it can handle overriding Equals without overriding ==, but that's OK).


Solution

  • it might work if you check that the types are nullable with this code:

    if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>)){}  
    

    The code sample is from here
    And if they are Nullable then you can call

    Nullable.Equals<T>(T? n1, T? n2);