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.
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
Musiałbym zablokować wystąpienie obiektu w delegata. Metody 'GetValue' i' SetValue' pobierają instancję obiektu w momencie wywołania. –
Delegate.CreateDelegate może tworzyć obiekty delegatów otwartych i zamkniętych. – Ani