Delegate for Generic Property.GetSetMethod

2019-04-28 07:05发布

问题:

I am trying to create a delegate for setting a property value of a generic, but I am getting an error: Error binding to target method when I try to execute the following code:

Action<T, object> setValue = (Action<T, object>) Delegate.CreateDelegate(
    typeof(Action<T, object>), null, property.GetSetMethod());

Is this even possible?

回答1:

Yes it is possible, you're just trying to create a delegate of the wrong type. The set method of a property only takes one argument, the value you're going to set. Also since its an instance method, you must pass the target object you want it to be bound to in the CreateDelegate call.

Example:

  var setValue = (Action<T>)Delegate.CreateDelegate( typeof( Action<T> ), target, property.GetSetMethod() );


回答2:

I think you want this:

Action<T, object> setValue = (t, o) => property.GetSetMethod().Invoke(t, new object[] { o });

or

Action<T, object> setValue = (t, o) => property.SetValue(t, o, null);

EDIT

To illustrate the assumed poorer performance of this answer compared to the accepted answer, assume this method:

void SetAnObjectPropertyOnALotOfObjects<T>(IEnumerable<T> objs)
{
    //Create a delegate and assign a reference to that delegate to the setValue variable
    Action<T, object> setValue = GetSetter();

    foreach (var o in objs)
    {
        //invoke the delegate referred to by the setValue variable (that is, "invoke its referent"
        setValue.Invoke(o, new object());
    }
}

MerickOWA's answer uses reflection in the GetSetter method, so we assume that the GetSetter method takes more time to execute, in his approach. This answer uses reflection each time we call setValue.Invoke, so we assume that takes more time to execute in this answer. If we assume the number of items in the sequence is large, MerickOWA's answer should require less time to execute.

For example, let's say that MerickOWA's GetSetter method takes X milliseconds more than mine to execute, while my setValue delegate takes Y milliseconds more than his. If there are N items in the sequence, then my solution should be slower than his by (N * Y - X) milliseconds.



回答3:

It depends. In my answer I assume two things:

  1. Your type "T" is the type of your class (which I will now denote as TClass)
  2. The type "object" is the type of your property (which I will now denote as TProperty)

Because your property is a non-static, there are two possibilies:

  1. An "normal" delegate with the target (instance) attached.
  2. An "open" delegate with in which a target is required as the first input parameter of the delegate.

A function to create such "normal" delegate is created as follows:

static public Action<TClass, TProperty> CreateSetPropertyDelegate<TClass, TProperty>(this PropertyInfo propertyInfo)
{
    return (Action<TClass, TProperty>)Delegate.CreateDelegate(typeof(Action<TClass, TProperty>), propertyInfo.GetSetMethod());
}

And in use (assuming the property type is of type int):

Action<int> setter = typeof(MyClass).GetProperty("MyProperty").CreateSetPropertyDelegate<MyClass, int>(myInsance);
setter(myPropertyValue);

A function to create an open delegate:

static public Action<TClass, TProperty> CreateSetPropertyDelegate<TClass, TProperty>(this PropertyInfo propertyInfo)
{
    return (Action<TClass, TProperty>)Delegate.CreateDelegate(typeof(Action<TClass, TProperty>), propertyInfo.GetSetMethod());
}

And in use:

Action<MyClass, int> setter = typeof(MyClass).GetProperty("MyProperty").CreateSetPropertyDelegate<MyClass, int>();
setter(myInsance, myPropertyValue);