Sebi Sebi - 1 year ago 69
C# Question

C# using ExpressionTree to set property value with different types

I have written a

extension Method to convert a DataTable to List. This just works under some circumstances but we have much old code which uses DataTables and sometimes it's needed. My Problem is that this method works with reflection what is ok but not that performant. I need about 1,2sek for 100.000 DataRows.

So i decided to build this with Expression Trees. At first i want to replace the Setter Call of Properties. Up to this time i could easily get the value:

var exactType = Nullable.GetUnderlyingType(propType) ?? propType;
var wert = Convert.ChangeType(zeile[spaltenname], exactType);

and set it:

propertyInfo.SetValue(tempObjekt, wert, null);

Now i searched StackOverflow and found this:

var zielExp = Expression.Parameter(typeof(T));
var wertExp = Expression.Parameter(propType);

var propertyExp = Expression.Property(zielExp, matchProp);
var zuweisungExp = Expression.Assign(propertyExp, wertExp);

var setter = Expression.Lambda<Action<T, int>>(zuweisungExp, zielExp, wertExp).Compile();
setter(tempObjekt, wert);

My big Problem is that the Lambda Action expects an integer. But i need this expecting the type of my Property. I have the Type of my Property via PropertyInfo. But can't get this to work. Thought i can easily make:

Action<T, object>

but this results in following excepion:

ArgumentException The ParameterExpression from Type "System.Int32"
cannot be used as Delegateparameter from Type "System.Object".

Someone out there knows a possible solution?

Answer Source

Instead of the generic Expression.Lambda method you can use this overload which takes a type:

public static LambdaExpression Lambda(
   Type delegateType,
   Expression body,
   params ParameterExpression[] parameters

Then you can use the Type.MakeGenericType method to create the type for your action:

var actionType = typeof(Action<,>).MakeGenericType(typeof(T), proptype);
var setter = Expression.Lambda(actionType, zuweisungExp, zielExp, wertExp).Compile();