0

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?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
  • 2
    Compiling a dynamic method is slower by far than using reflection if you do it every time. I think you need to cache the setter. – usr Jun 18 '12 at 13:37
  • @usr: True, but I can worry about caching it later. For now I need to create it first. – Stefan Steiger Jun 18 '12 at 13:51

2 Answers2

1

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();
}
L.B
  • 114,136
  • 19
  • 178
  • 224
0

Make the parameter ob type object and make the lambda cast to the correct field-type internally.

Or, construct the delegate type (Action) dynamically at runtime.

Or, you could define SetValue as follows:

SetValue<TObject, TProperty>

That would make this method generic over the property type.

Edit: It sounds like option 1 is best for you. You need to change the parameter type to typeof(object) and add a cast:

valueExp = Expression.Convert(valueExp, field.FieldType)

And you need to use Action<T, object> as the delegate type.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I know. But HOW !!! As for SetValue: Then I would need the field/property type at compile time again, which I can't have, since the type is different for each field. Same problem really, just without Lambda expression. – Stefan Steiger Jun 18 '12 at 13:46
  • Ok I added some instructions. That is really all there is to it. – usr Jun 18 '12 at 13:58