Refleksja szczególnie na temat członków prywatnych jest błędna
- Odbicie przerywa bezpieczeństwo typu. Możesz spróbować wywołać metodę, która nie istnieje (już), albo z niewłaściwymi parametrami, albo ze zbyt dużą liczbą parametrów, albo za mało ... lub nawet w niewłaściwej kolejności (ta moja ulubiona :)). Nawiasem mówiąc, typ zwrotu może się również zmienić.
- Odbicie jest powolne.
Odbicie członków prywatnych łamie zasadę enkapsulacji, a tym samym naraża Twój kod na:
- Zwiększ złożoność swojego kodu, ponieważ musi on obsługiwać wewnętrzne zachowanie klas. To, co jest ukryte, powinno pozostać ukryte.
- Ułatwia złamanie kodu, ponieważ będzie się kompilował, ale nie będzie działać, jeśli metoda zmieni nazwę.
- Sprawia, że kod prywatny jest łatwy do złamania, ponieważ jeśli jest prywatny, nie jest przeznaczony do takiego wywoływania. Być może metoda prywatna oczekuje jakiegoś stanu wewnętrznego przed wywołaniem.
Co jeśli i tak muszę to zrobić?
Zdarzają się przypadki, w których zależysz na stronie trzeciej lub potrzebujesz nieosłoniętego interfejsu API, musisz się zastanowić. Niektórzy używają go również do testowania posiadanych klas, ale nie chcą zmieniać interfejsu, aby dać dostęp do wewnętrznych elementów tylko na potrzeby testów.
Jeśli to zrobisz, zrób to dobrze
- Łagodź łatwe do złamania:
Aby złagodzić problem łatwej do złamania, najlepiej jest wykryć potencjalną przerwę, testując w testach jednostkowych, które działałyby w kompilacji ciągłej lub podobnej. Oczywiście oznacza to, że zawsze używasz tego samego zestawu (który zawiera członków prywatnych). Jeśli używasz obciążenia dynamicznego i odbicia, lubisz bawić się ogniem, ale zawsze możesz uchwycić wyjątek, który może wywołać połączenie.
- Łagodź powolność refleksji:
W najnowszych wersjach .Net Framework CreateDelegate pokonał 50-krotnie metodę MethodInfo:
// The following should be done once since this does some reflection
var method = this.GetType().GetMethod("Draw_" + itemType,
BindingFlags.NonPublic | BindingFlags.Instance);
// Here we create a Func that targets the instance of type which has the
// Draw_ItemType method
var draw = (Func<TInput, Output[]>)_method.CreateDelegate(
typeof(Func<TInput, TOutput[]>), this);
draw
Połączenia będzie około 50x szybciej niż MethodInfo.Invoke
wykorzystania draw
jako standard Func
tak:
var res = draw(methodParams);
Sprawdź mój post, aby zobaczyć wyniki testów wywoływania różnych metod