Un delegato aperto è un delegato a un metodo di istanza senza la destinazione. Per chiamarlo fornisci il bersaglio come primo parametro. Sono un modo intelligente per ottimizzare il codice che altrimenti userebbe la riflessione e ha prestazioni scadenti. Per un'introduzione ai delegati aperti vedere this. Il modo in cui lo useresti in pratica è avere un costoso codice di riflessione per costruire questi delegati aperti, ma in questo caso potresti chiamarli molto a buon mercato come una semplice chiamata Delegate.Creazione di un delegato aperto performante per un setter o getter di proprietà
Sto provando a scrivere il codice che trasformerà un PropertyInfo arbitrario, in un tale delegato per il suo setter. Finora mi è venuta questa idea:
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);
}
}
}
Il codice simile sarebbe stato scritto per il getter. Funziona, ma il delegato setter usa un DynamicInvoke per convertire da un'azione <derivedType
> all'azione <object
>, che sospetto stia mangiando buona parte dell'ottimizzazione che sto cercando. Quindi le domande sono:
- Il DynamicInvoke è una preoccupazione reale?
- C'è comunque intorno?
Puoi approfondire la vostra risposta? 1-Cosa intendi per "Riflessione contro un generico tipo interiore"; 2 - Come potrebbe aiutarmi l'API di Expression? –
@David - esempio di espressione aggiunto. Eseguirò un esempio di tipo interno generico –
@David e aggiunto l'esempio di tipo generico interno –