Created
May 11, 2012 07:52
-
-
Save danielwertheim/2658225 to your computer and use it in GitHub Desktop.
ExpressionComparer does not support AnonymousTypes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static LambdaExpression ExpressionFactory(int customerNoFrom, int customerNoTo) | |
{ | |
Func<Expression<Func<Customer, bool>>, LambdaExpression> fn = expression => expression; | |
return fn(c => | |
c.CustomerNo >= customerNoFrom && c.CustomerNo <= customerNoTo && | |
c.DeliveryAddress.Street == "The delivery street #544"); | |
} | |
static void Main(string[] args) | |
{ | |
var e1 = ExpressionFactory(500, 550); | |
var e2 = ExpressionFactory(500, 550); | |
var r = ExpressionComparer.AreEqual(e1, e2); //Gives false | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//In ExpressionComparer | |
protected virtual bool CompareConstant(ConstantExpression a, ConstantExpression b) | |
{ | |
if (this.fnCompare != null) | |
{ | |
return this.fnCompare(a.Value, b.Value); | |
} | |
else | |
{ | |
return object.Equals(a.Value, b.Value) || CompareAnonymous(a.Type, a.Value, b.Value); //ADDED | |
} | |
} | |
protected virtual bool CompareAnonymous(Type t, object a, object b) | |
{ | |
//TODO: Add check if anonymous type before passing on call | |
return TypeCompares.Get(t).AreEqual(a, b); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//NEEDS TO BE EXTENDED WITH TRAVERSAL OF ENUMERABLES ETC!!! | |
public static class TypeCompares | |
{ | |
private static readonly ConcurrentDictionary<Type, TypeCompare> Comparers = new ConcurrentDictionary<Type, TypeCompare>(); | |
public static TypeCompare Get(Type t) | |
{ | |
return Comparers.GetOrAdd(t, new TypeCompare(t)); | |
} | |
} | |
public class TypeCompare | |
{ | |
private readonly DynamicFieldGetter[] PublicFields; | |
public TypeCompare(Type type) | |
{ | |
PublicFields = type.GetFields().Select(DynamicFieldFactory.GetterFor).ToArray(); | |
} | |
public bool AreEqual(object x, object y) | |
{ | |
if (object.ReferenceEquals(x, y)) | |
return true; | |
if (x == null && y == null) | |
return true; | |
if (x == null) | |
return false; | |
if (y == null) | |
return false; | |
foreach (var field in PublicFields) | |
{ | |
var xv = field.GetValue(x); | |
var yv = field.GetValue(y); | |
if (!object.Equals(xv, yv)) | |
return false; | |
} | |
return true; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class DynamicFieldGetter | |
{ | |
private readonly Func<object, object> _accessor; | |
public DynamicFieldGetter(Func<object, object> accessor) | |
{ | |
_accessor = accessor; | |
} | |
public object GetValue<T>(T item) | |
{ | |
return _accessor(item); | |
} | |
} | |
public static class DynamicFieldFactory | |
{ | |
private static readonly Type ObjectType = typeof(object); | |
private static readonly Type IlGetterType = typeof(Func<object, object>); | |
public static DynamicFieldGetter GetterFor(FieldInfo p) | |
{ | |
if (p.DeclaringType.IsKeyValuePairType()) | |
return new DynamicFieldGetter(CreateLambdaGetter(p.DeclaringType, p)); | |
return new DynamicFieldGetter(CreateIlGetter(p)); | |
} | |
private static Func<object, object> CreateLambdaGetter(Type type, FieldInfo property) | |
{ | |
var objExpr = Expression.Parameter(ObjectType, "theItem"); | |
var castedObjExpr = Expression.Convert(objExpr, type); | |
var p = Expression.Field(castedObjExpr, property); | |
var castedProp = Expression.Convert(p, ObjectType); | |
var lambda = Expression.Lambda<Func<object, object>>(castedProp, objExpr); | |
return lambda.Compile(); | |
} | |
private static Func<object, object> CreateIlGetter(FieldInfo propertyInfo) | |
{ | |
var getter = CreateDynamicGetMethod(propertyInfo); | |
var generator = getter.GetILGenerator(); | |
generator.DeclareLocal(ObjectType); | |
generator.Emit(OpCodes.Ldarg_0); | |
generator.Emit(OpCodes.Castclass, propertyInfo.DeclaringType); | |
generator.Emit(OpCodes.Ldfld, propertyInfo); | |
if (!propertyInfo.FieldType.IsClass) | |
generator.Emit(OpCodes.Box, propertyInfo.FieldType); | |
generator.Emit(OpCodes.Ret); | |
return (Func<object, object>)getter.CreateDelegate(IlGetterType); | |
} | |
private static DynamicMethod CreateDynamicGetMethod(FieldInfo propertyInfo) | |
{ | |
var args = new[] { ObjectType }; | |
var name = string.Format("_{0}{1}_", "Get", propertyInfo.Name); | |
var returnType = ObjectType; | |
return !propertyInfo.DeclaringType.IsInterface | |
? new DynamicMethod( | |
name, | |
returnType, | |
args, | |
propertyInfo.DeclaringType, | |
true) | |
: new DynamicMethod( | |
name, | |
returnType, | |
args, | |
propertyInfo.Module, | |
true); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment