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?

2
  • 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. Commented Jun 18, 2012 at 13:37
  • @usr: True, but I can worry about caching it later. For now I need to create it first. Commented Jun 18, 2012 at 13:51

2 Answers 2

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();
}
Sign up to request clarification or add additional context in comments.

1 Comment

I tried that, but missed Expression.Convert. Nice, works - thanks !
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.

2 Comments

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.
Ok I added some instructions. That is really all there is to it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.