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