10

I'm trying to improve my reflection code by creating Delegates for the Getter and Setter methods.

My code looks like this:

MyObject obj = new MyObject();
var prop = obj.GetType().GetProperty("Prop");
var getType = typeof(Func<>).MakeGenericType(prop.PropertyType);
var setType = typeof(Action<>).MakeGenericType(prop.PropertyType);

var getMethod = prop.GetGetMethod().CreateDelegate(getType, obj);
var setMethod = prop.GetSetMethod().CreateDelegate(setType, obj);

// I'd like to change this section and not to use a dynamic!!
dynamic castedGet = Convert.ChangeType(getMethod, getType);
dynamic castedSet = Convert.ChangeType(setMethod, setType);

CreateDelegate returns a Delegate and using DynamicInvoke isn't performance wise.

I casted (hardcoded) the Delegate into Action<T> \ Func<T> and saw a huge increase in my performance.

I then tried to cast the Delegate into Action<T> \ Func<T> in runtime (using Convert.ChangeType and dynamic) and my performance got hurt - probably due to the fact that I'm using a dynamic type.

I'm pretty sure that I can do this without dynamic.

I guess the solution has something to do with expression trees, but I'm not really sure how to code something like this. If someone has a good solution that doesn't use expression trees than it will be interesting to hear about it as well.

Amir Popovich
  • 29,350
  • 9
  • 53
  • 99
  • Are you executing all of this code *every* time, or caching the delegates somewhere and then calling them? – Dai Sep 21 '15 at 15:03
  • @Dai - This is a small portion of my code and kind of a sample. I'm looking to cache the propertyinfo, getter, setter for each property - in a lazy way. – Amir Popovich Sep 21 '15 at 15:05
  • Why are you using `dynamic` anyway? `Convert.ChangeType` does not return a late-bound object. – Dai Sep 21 '15 at 15:05
  • @Dai - I'm using a dynamic since I want to somehow invoke the methods. – Amir Popovich Sep 21 '15 at 15:07
  • Here is expression tree answer - http://stackoverflow.com/questions/536932/how-to-create-expression-tree-lambda-for-a-deep-property-from-a-string – Alexei Levenkov Sep 21 '15 at 15:16
  • So, basically what you want is to instantiate an object with dynamic template argument? – Matteo Umili Sep 21 '15 at 15:22
  • @AlexeiLevenkov - While it's close to what I need it's not exactly what I'm looking for. I've tried to customize it to work on my end and couldn't. Thanks for the useful link. – Amir Popovich Sep 21 '15 at 15:33
  • @codroipo - Not really. I'm trying to cache the getter and setter of my properties and want to compile their delegates into Actions\Funcs in runtime based on their property type. – Amir Popovich Sep 21 '15 at 15:34
  • @AmirPopovich: When you want to invoke the getter/setter methods later, will you be in a context where your code knows the name or type of the value you're expecting? Or is the purpose to enable compile-time code to use `object` values, when you know that the values will be of the correct type at runtime? Perhaps it would help to explain what you envision the code looking like that would invoke the resulting `Action<>` and retrieving the value from the resulting `Func<>`. – StriplingWarrior Sep 21 '15 at 18:00

2 Answers2

3

If your objective is to be able to invoke your action/function without knowing the return type at compile time, then you probably want to end up with an Action<object> and Func<object>, right?

You can do this without having to compile an expression tree or anything, like so:

// Use reflection to create the action, invoking the method below.
var setAction = (Action<object>) this.GetType()
    .GetMethod("CastAction", BindingFlags.Static | BindingFlags.NonPublic)
    .MakeGenericMethod(prop.PropertyType)
    .Invoke(null, new object[]{setMethod});

// invoke the action like this:
object value = 42; // or any value of the right type.
setAction(value);

Using this helper method:

private static Action<object> CastAction<T>(Delegate d)
{
    var action = (Action<T>)d;
    return obj => action((T)obj);
}

My tests show this to be roughly 25% faster than using dynamic, and about 45% slower than just saying obj.Prop = 2;

StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
  • What's the difference between @k3b answer? OP said that "Using MethodInfo.Invoke is a lot slower than creating delegates and invoking them" – Matteo Umili Sep 21 '15 at 19:59
  • @codroipo: In this case, I'm using `MethodInfo.Invoke()` only to create the delegate in the first place. This is something the OP's `ChangeType` method is effectively doing under the covers. The resulting `setAction` action, however, can be invoked far more quickly than calling `setter.Invoke()`, as k3b's answer does. And it is somewhat quicker than calling the dynamic `castedSet` action, because it's not relying on a dynamic invocation. – StriplingWarrior Sep 21 '15 at 20:21
  • 1
    @StriplingWarrior - This is very interesting. The benchmarks are better than using a dynamic and slower than using the hard coded casting. Currently this is the fastest generic way I have. Thank you for your answer. I'm waiting for some more answers and will accept if there is nothing better. Thanks!!!! +1. – Amir Popovich Sep 22 '15 at 06:59
  • 1
    @StriplingWarrior ok, this morning, with mind fresh I understand what you do. Definetly +1 – Matteo Umili Sep 22 '15 at 08:15
1

Is there a reason why you need to use Action<T> or Func<T> to dynamically get/set a propery?

If not you can use PropertyInfo.GetMethod() and SetMethod()

 MyObject obj = new MyObject();
 PropertyInfo prop = obj.GetType().GetProperty("Prop");

 MethodInfo getter = prop.GetMethod();
 getter.Invoke(...)

 MethodInfo setter = prop.SetMethod();
 setter.Invoke(...)
k3b
  • 14,517
  • 7
  • 53
  • 85
  • 1
    The reason is performance. Using MethodInfo.Invoke is a lot slower than creating delegates and invoking them (assume that I want to cache them). Thanks anyway. – Amir Popovich Sep 21 '15 at 15:11
  • 1
    I was not aware (and never thought of and never checked myself) that `Invoke()` is slower than ducktyping using `dynamic` – k3b Sep 21 '15 at 15:16