2011-11-10 14 views
6

Sto cercando di creare un delegato per l'impostazione di un valore di proprietà di un generico, ma sto ottenendo un errore: Error binding to target method quando si tenta di eseguire il codice seguente:delegato per Property.GetSetMethod Generico

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

Is questo è possibile?

+0

La tua proprietà è di proprietà statica? In caso contrario, non è possibile passare nulla. – phoog

+0

No, non è dispiaciuto, mi spiace di aver perso quel pezzo, ma anche quando passo in un'istanza della classe non funziona correttamente, ottengo comunque la stessa eccezione – ChandlerPelhams

risposta

3

Sì, è possibile, stai solo provando a creare un delegato del tipo sbagliato. Il metodo set di una proprietà prende solo un argomento, il valore che si intende impostare. Inoltre, poiché è un metodo di istanza, è necessario passare l'oggetto target a cui si desidera associare nella chiamata CreateDelegate.

Esempio:

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

Penso che si desidera questo:

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

o

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

EDIT

Per illustrare l'andamento peggiore assunto di questa risposta rispetto alla risposta accettata, assumere questo metodo :

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()); 
    } 
} 

La risposta di MerickOWA utilizza la riflessione nel metodo GetSetter, pertanto si assume che il metodo GetSetter richieda più tempo per l'esecuzione, nel suo approccio. Questa risposta utilizza la riflessione ogni volta che chiamiamo setValue.Invoke, quindi assumiamo che ci vuole più tempo per eseguire questa risposta. Se assumiamo che il numero di elementi nella sequenza sia ampio, la risposta di MerickOWA dovrebbe richiedere meno tempo per l'esecuzione.

Ad esempio, diciamo che il metodo GetSetter di MerickOWA impiega X millisecondi più del mio per essere eseguito, mentre il mio delegato setValue richiede Y millisecondi più del suo. Se ci sono N elementi nella sequenza, la mia soluzione dovrebbe essere più lenta del suo da (N * Y - X) millisecondi.

+0

Questo usa il PropertyInfo per impostare il valore ogni volta, questo è molto più lento rispetto a ciò che CreateDelegate restituirebbe – MerickOWA

+0

Ah, naturalmente (schiaffo la mia testa) – phoog

+0

Puoi dirmi perché questo metodo sarebbe più lento? Nei miei test, lambda si è esibita in metà tempo di creare delegati. – nawfal

1

Dipende. Nella mia risposta presumo due cose:

  1. tuo tipo "T" è il tipo della classe (che io ora indicare come TClass)
  2. Il tipo di "oggetto" è il tipo di vostra proprietà (che Passo ora denotano come TProperty)

Perché la vostra proprietà è un non-statico, ci sono due possibilies:

  1. un delegato di "normale" con il target (esempio) in allegato.
  2. Un delegato "aperto" con in cui è richiesto un target come primo parametro di input del delegato.

Una funzione di creare tale delegato "normale" viene creato come segue:

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

ed in uso (assumendo che il tipo di proprietà è di tipo int):

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

Una funzione creare un delegato aperto:

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

E in uso:

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