2011-11-10 17 views
6

Próbuję utworzyć delegata do ustawiania wartości właściwości rodzajowy, ale otrzymuję błąd: Error binding to target method gdy próbuję wykonać następujący kod:Delegat Generic Property.GetSetMethod

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

Czy to nawet możliwe?

+0

Czy Twoja nieruchomość to nieruchomość statyczna? Jeśli nie, to nie możesz przekazać wartości null. – phoog

+0

Nie, nie, przepraszam, że przegapiłem ten fragment, ale nawet gdy przekazuję instancję klasy, to nie działa poprawnie, nadal otrzymuję ten sam wyjątek. – ChandlerPelhams

Odpowiedz

3

Tak, jest możliwe, po prostu próbujesz utworzyć delegata niewłaściwego typu. Ustawiona metoda właściwości przyjmuje tylko jeden argument, wartość, którą zamierzasz ustawić. Również od metody instancji musisz przekazać obiekt docelowy, do którego ma być przypisany, w wywołaniu CreateDelegate.

przykład:

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

Myślę, że chcesz to:

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

lub

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

EDIT

Aby zilustrować zakładany gorszą wydajność tej odpowiedzi w porównaniu z przyjętym odpowiedź, przyjąć tę metodę :

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

Odpowiedź MerickOWY wykorzystuje odbicie w metodzie GetSetter, więc przyjmujemy, że metoda GetSetter wymaga więcej czasu, aby wykonać ją w swoim podejściu. Ta odpowiedź używa refleksji za każdym razem, gdy dzwonimy pod numer setValue.Invoke, więc przyjmujemy, że wykonanie tej odpowiedzi zajmuje więcej czasu. Jeśli założymy, że liczba pozycji w sekwencji jest duża, odpowiedź MerickOWA powinna wymagać mniej czasu na wykonanie.

Na przykład, powiedzmy, że metoda GetSetter firmy MerickOWA zajmuje mi X milisekundy więcej niż moje, podczas gdy mój delegat setValue zajmuje Y milisekund więcej niż jego. Jeśli w sekwencji jest N pozycji, moje rozwiązanie powinno być wolniejsze niż jego (N * Y - X) milisekund.

+0

To wykorzystuje PropertyInfo do ustawienia wartości za każdym razem, jest to znacznie wolniejsze niż to, co CreateDelegate zwróci – MerickOWA

+0

Ah, oczywiście (klepiąc mnie w głowę) – phoog

+0

Czy możesz mi powiedzieć, dlaczego ta metoda byłaby wolniejsza? W moich testach lambda wykonała połowę czasu delegowania tworzenia. – nawfal

1

Zależy. W mojej odpowiedzi Zakładam dwie rzeczy:

  1. Twój typ „T” jest typem klasy (które będę teraz oznaczymy jako tclass)
  2. „Obiekt” typ jest typem nieruchomości (co będę teraz oznaczymy jako TProperty)

Ponieważ własność jest non-static, istnieją dwa possibilies:

  1. Określenie "normalne" delegat z celem (instancja) w załączeniu.
  2. "Otwarty" uczestnik, w którym wymagany jest cel jako pierwszy parametr wejściowy uczestnika.

Funkcja stworzyć taki "normalny" delegata jest tworzony w następujący sposób:

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

I w użyciu (zakładając rodzaj własności jest typu int):

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

Funkcja Aby utworzyć otwartego uczestnika:

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

I w użyciu:

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