Un delegado abierto es un delegado en un método de instancia sin el destino. Para invocarlo, proporciona el objetivo como primer parámetro. Son una manera inteligente de optimizar el código que de otra forma usaría la reflexión y tendría un rendimiento deficiente. Para una introducción para abrir delegados, vea this. La forma en que lo usaría en la práctica es tener un código de reflexión costoso para construir estos delegados abiertos, pero luego podría llamarlos de forma muy económica como una simple llamada de delegado.Creación de un delegado abierto de rendimiento para un creador o definidor de propiedad
Estoy tratando de escribir código que transformará un PropertyInfo arbitrario, en un delegado así para su setter. Hasta ahora se me ocurrió esto:
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);
}
}
}
Se escribirá un código similar para el captador. Funciona, pero el delegado del colocador utiliza un DynamicInvoke para convertir de una Acción <derivedType
> a la Acción <object
>, que sospecho que se está comiendo una buena parte de la optimización que estoy buscando. Entonces las preguntas son:
- ¿Es el DynamicInvoke una preocupación real?
- ¿Hay alguna manera alrededor?
Se puede elaborar en su respuesta? 1-¿Qué quiere decir con "Reflexión contra un tipo interno genérico"; 2 - ¿Cómo me ayudaría la API Expression? –
@David - ejemplo de expresión agregado. Voy a batir un ejemplo de tipo interno genérico –
@David - y agregué el ejemplo de tipo genérico interno –