2012-10-07 16 views
15

Dlaczego metody pobierania i ustawiania właściwości są tak wolne? Jeśli zbuduję delegata przy użyciu Reflection.Emit, jest to znacznie szybsze.Dlaczego właściwości PropertyInfo SetValue i GetValue są takie wolne?

Czy robią coś ważnego, aby czas, który biorą, może być usprawiedliwiony? To jest ... czy brakuje mi czegoś, używając Reflection.Emit do budowania delegatów zamiast usign GetValue i SetValue z PropertyInfo (poza szybkością programowania)?

PS: Proszę, przedstaw dowody, nie tylko zgadywanie!

+3

FYI, jeśli szukasz łatwiejszy sposób coraz większą wydajność niż Reflection.Emit, można po prostu Delegate.CreateDelegate z PropertyInfo.GetGetMethod/PropertyInfo.GetSetMethod (i buforować delegata oczywiście). – Ani

+0

Musiałbym zablokować wystąpienie obiektu w delegata. Metody 'GetValue' i' SetValue' pobierają instancję obiektu w momencie wywołania. –

+0

Delegate.CreateDelegate może tworzyć obiekty delegatów otwartych i zamkniętych. – Ani

Odpowiedz

16

Realizacja RuntimePropertyInfo (co jest beton podklasa PropertyInfo dla typów uruchomieniowych) realizuje GetValue i SetValue przez wywoływanie metod getter i setter poprzez odbicie (MethodInfo.Invoke), podczas gdy Twój generowane delegat prawdopodobnie wywołuje metody bezpośrednio. Dlatego pytanie sprowadza się do: dlaczego RuntimeMethodInfo.Invoke jest tak powolny w porównaniu do skompilowanego wywołania?

Kiedy dekompilować (lub spojrzeć na źródła odniesienia dla) RuntimeMethodInfo.Invoke, można zobaczyć, że jest to prawdopodobnie dlatego Invoke realizuje wiele zadań:

  • wykonuje sprawdzanie spójności (do liczby i rodzajów przekazanych parametrów pasuje do sygnatury? czy przekazana instancja pasuje do typu deklarującego? czy instancja przeszła mimo, że metoda jest statyczna?),
  • wykonuje widoczność i (jeśli obejmie się kontrolę widoczności) kontrole bezpieczeństwa,
  • rozpakowuje tablica parametrów, traktująca ref pa rametrów w specjalny sposób, tak że mogą być one zapisywane na później,
  • to unboxes parametry, jeśli to konieczne,
  • musi znaleźć wskaźnik metoda oparta na uchwycie typu Runtime rączką i metody związanej ze RuntimeMethodHandle a następnie powołać metoda ta, jeśli to konieczne, powoduje umieszczenie wartości zwracanej, a następnie umieszcza w tablicy parametrów wszystkie parametry ref/out.

Środowisko wykonawcze będzie wykonywać podobną spójność, bezpieczeństwo i kontrolę widoczności podczas kompilowania delegata w wykonywalny kod natywny. Emituje również kod do boksowania/rozpakowywania itp. Jednakże, musi tylko wykonać te czynności raz, a następnie może zagwarantować, że kod jest bezpieczny do wykonania. To sprawia, że ​​rzeczywista metoda nazywa się bardzo tanią operacją (załaduj parametry i przejdź do adresu metody).

Natomiast każde wezwanie do RuntimeMethodInfo.Invoke (a więc do GetValue/SetValue) musi powtarzać całą pracę, od kontekstu - parametry, przykład i użytkowania zwracanego typu - nie jest znane. I prawdopodobnie dlatego jest tak powolny.

Informacje o tym, czego może brakować: jeśli emitujesz własnych delegatów wywołań właściwości, musisz oczywiście zająć się boksem/rozpakowywaniem, parametrami ref/out itp.

10

Nie trzeba używać Emit. O wiele łatwiej jest używać wyrażenia. Możesz przyspieszyć dostęp, jak opisano w SO. Klasa pomocnika tworzy "wskaźnik metody" (Action/Func) dla pobierającego lub ustawiającego. Jeśli ponownie wykorzystasz Action/Func, będziesz mógł wykonać tak szybko, jak normalny seter.

// creating setter (once) 
    var propertyInfo = typeof(T).GetProperty(field); 
    var setter = FastInvoke.BuildUntypedSetter<T>(propertyInfo)); 

    // usage somehow later in a loop of data 
    foreach(var myobject in MySource) 
    { 
    setter(myobject, myValue) 
    } 
+0

http://stackoverflow.com/questions/1027980/improving-performance-reflection-what-alternatives- mógłby rozważyć –

+0

@ sky-dev: O co ci chodzi? – Fried

+0

@Fried Twój link jest zepsuty, podczas gdy link sky-devs działa. Myślę, że to jest jego punkt. – ViRuSTriNiTy

Powiązane problemy