Search code examples
c#.netlinqgenericslinq-expressions

How to create a lambda expression from a type object with LINQ?


I'm trying to speed up reflection -> SetValue with a LINQ expression.

My problem is this method:

public void SetValue<T>(T obj)
{
    FieldInfo field = typeof(T).GetField("Title", BindingFlags.Instance |
                                                  BindingFlags.Public |
                                                  BindingFlags.IgnoreCase);

    ParameterExpression targetExp = Expression.Parameter(typeof(T), "target");
    ParameterExpression valueExp = Expression.Parameter(field.FieldType, "value");

    // Expression.Property can be used here as well
    MemberExpression fieldExp = Expression.Field(targetExp, field);
    BinaryExpression assignExp = Expression.Assign(fieldExp, valueExp);

    var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile();

    setter(obj, "Hello World");

    //Console.WriteLine(obj.title);
}

which I call like this:

var ii = new Controllers.SearchController.InstantItem();

SetValue<Controllers.SearchController.InstantItem>(ii);

The problem is this line:

var setter = Expression.Lambda<Action<T, string>>(assignExp, targetExp, valueExp).Compile();

Because Action uses generics, I cannot replace string with field.FieldType...

Is there any possibility I can do this without having to make a switch(field.FieldType) statement, and put a generic method for each possible type, which would suck big time?


Solution

  • Maybe something like this

    action = FormAction(fieldInfo);
    action(obj,valueToSet);
    

    Of course caching the Actions in a dictionary will be needed.

    static Action<object, object> FormAction(FieldInfo fieldInfo)
    {
        ParameterExpression obj = Expression.Parameter(typeof(object), fieldInfo.Name);
        ParameterExpression value = Expression.Parameter(typeof(object));
    
        MemberExpression fieldExp = Expression.Field(Expression.Convert(obj, fieldInfo.DeclaringType), fieldInfo.Name);
        BinaryExpression assignExp = Expression.Assign(fieldExp, Expression.Convert(value, fieldInfo.FieldType));
    
        return Expression.Lambda<Action<object, object>>(assignExp, obj, value).Compile();
    }