Открытый делегат является делегатом метода экземпляра без цели. Чтобы вызвать его, вы указываете цель в качестве ее первого параметра. Это умный способ оптимизации кода, который в противном случае использовал бы отражение и имел бы низкую производительность. Для вступления в открытые делегаты см. this. То, как вы будете использовать его на практике, - это иметь дорогой код отражения для создания этих открытых делегатов, но тогда вы сможете назвать их очень дешево, как простой вызов делегата.
Я пытаюсь написать код, который преобразует произвольное PropertyInfo, в такой делегат для его сеттера. До сих пор я придумал это:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
namespace Test
{
class TestClass
{
static Action<T, object> MakeSetterDelegate<T>(PropertyInfo property)
{
MethodInfo setMethod = property.GetSetMethod();
if (setMethod != null && setMethod.GetParameters().Length == 1) //skips over nasty index properties
{
//To be able to bind to the delegate we have to create a delegate
//type like: Action<T,actualType> rather than Action<T,object>.
//We use reflection to do that
Type setterGenericType = typeof(Action<,>);
Type delegateType = setterGenericType.MakeGenericType(new Type[] { typeof(T), property.PropertyType });
var untypedDelegate = Delegate.CreateDelegate(delegateType, setMethod);
//we wrap the Action<T,actualType> delegate into an Action<T,object>
Action<T, object> setter = (instance, value) =>
{
untypedDelegate.DynamicInvoke(new object[] { instance, value });
};
return setter;
}
else
{
return null;
}
}
int TestProp
{
set
{
System.Diagnostics.Debug.WriteLine("Called set_TestProp");
}
}
static void Test()
{
PropertyInfo property = typeof(TestClass).GetProperty("TestProp");
Action<TestClass, object> setter = MakeSetterDelegate<TestClass>(property);
TestClass instance = new TestClass();
setter(instance, 5);
}
}
}
Аналогичный код будет написан для получателя. Он работает, но делегат setter использует DynamicInvoke для преобразования из Action <derivedType
> в Action <object
> , который, как я подозреваю, питается хорошей частью оптимизации, которой я пользуюсь. Итак, вопросы:
- Является ли DynamicInvoke реальной проблемой?
- Есть ли все-таки вокруг?