2015-09-21 14 views
8

Sto cercando di migliorare il mio codice di riflessione creando delegati per i metodi Getter e Setter.Trasferimento di un delegato in un'azione <T> o Func <T> in runtime

Il mio codice è simile al seguente:

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 restituisce un Delegate e utilizzando DynamicInvokenon è prestazioni saggio.

Ho fuso (codificato) lo Delegate in Action<T> \ Func<T> e ho visto un enorme aumento delle mie prestazioni.

Allora ho provato a gettare il Delegate in Action<T> \ Func<T> in fase di esecuzione (utilizzando Convert.ChangeType e dynamic) e la mia prestazione è fatto male - probabilmente a causa del fatto che sto usando un tipo dynamic.

Sono abbastanza sicuro di poterlo fare senza dynamic.

mi immagino la soluzione ha qualcosa a che fare con expression trees, ma non sono davvero sicuro di come codificare qualcosa di simile. Se qualcuno ha una buona soluzione che non usa expression trees allora sarà interessante sentirlo anche su di esso.

+0

Stai eseguendo tutto questo codice * ogni * volta, o memorizzando nella cache i delegati da qualche parte e quindi chiamandoli? – Dai

+0

@Dai - Questa è una piccola porzione del mio codice e una specie di campione. Sto cercando di mettere in cache il propertyinfo, getter, setter per ogni proprietà - in modo pigro. –

+0

Perché stai usando 'dynamic' comunque? 'Convert.ChangeType' non restituisce un oggetto tardivo. – Dai

risposta

3

Se il vostro obiettivo è quello di essere in grado di richiamare la vostra azione/funzione senza conoscere il tipo di ritorno al momento della compilazione, allora probabilmente si vuole finire con un Action<object> e Func<object>, giusto?

È possibile fare questo senza dover compilare un albero di espressione o nulla, in questo modo:

// 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); 

Usando questo metodo di supporto:

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

mio test mostrano che questo è circa il 25% più veloce che usare dynamic e circa il 45% più lento del semplice obj.Prop = 2;

+0

Qual è la differenza tra @ k3b answer? OP ha detto che "L'uso di MethodInfo.Invoke è molto più lento della creazione di delegati e invocarli" –

+0

@codroipo: In questo caso, sto utilizzando 'MethodInfo.Invoke()' solo per creare il delegato in primo luogo. Questo è qualcosa che il metodo 'ChangeType' dell'OP sta effettivamente facendo sotto le coperte. L'azione risultante 'setAction', tuttavia, può essere invocata molto più rapidamente che chiamare' setter.Invoke() ', come fa la risposta di k3b. Ed è un po 'più veloce di chiamare l'azione dinamica 'castedSet', perché non si basa su un'invocazione dinamica. – StriplingWarrior

+1

@StriplingWarrior - Questo è molto interessante. I parametri di riferimento sono migliori rispetto all'utilizzo di un metodo dinamico e più lento rispetto all'utilizzo della trasmissione codificata. Attualmente questo è il modo più generico più veloce che ho. La ringrazio per la risposta. Sto aspettando altre risposte e accetterò se non c'è niente di meglio. Grazie!!!! +1. –

1

C'è un motivo per cui è necessario utilizzare l'azione < T> o Func < T> per ottenere/impostare dinamicamente una proprietà?

Se non è possibile utilizzare PropertyInfo.GetMethod() e SetMethod()

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

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

MethodInfo setter = prop.SetMethod(); 
setter.Invoke(...) 
+0

Il motivo è la prestazione. L'utilizzo di MethodInfo.Invoke è molto più lento rispetto alla creazione di delegati e al loro richiamo (si supponga di volerli memorizzare nella cache). Grazie comunque. –

+1

Non ero a conoscenza (e non ho mai pensato e mai controllato) che 'Invoke()' sia più lento di ducktyping usando 'dynamic' – k3b