Отражение, особенно в отношении частных лиц, неверно
- Отражение нарушает безопасность типов. Вы можете попытаться вызвать метод, который не существует (больше), или с неправильными параметрами, или с слишком большим количеством параметров, или недостаточно ... или даже в неправильном порядке (этот мой любимый :)). Кстати, тип возвращаемого значения также может измениться.
- Отражение медленное.
Отражение закрытых членов нарушает принцип инкапсуляции и, таким образом, предоставляет вашему коду следующее:
- Увеличить сложность вашего кода, потому что он должен обрабатывать внутреннее поведение классов. То, что скрыто, должно оставаться скрытым.
- Облегчает взлом вашего кода, так как он будет компилироваться, но не будет работать, если метод изменил свое имя.
- Позволяет легко взломать приватный код, потому что если он приватный, его не следует называть таким образом. Возможно, закрытый метод ожидает некоторое внутреннее состояние перед вызовом.
Что если я все равно должен это сделать?
Бывают случаи, когда вы зависите от третьей стороны или вам нужно, чтобы какой-то API-интерфейс не был раскрыт, вам нужно подумать. Некоторые также используют его для тестирования некоторых классов, которыми они владеют, но они не хотят менять интерфейс, чтобы предоставить доступ к внутренним элементам только для тестов.
Если вы делаете это, делайте это правильно
Чтобы смягчить проблему, которую легко сломать, лучше всего обнаружить любой потенциальный сбой путем тестирования в модульных тестах, которые будут выполняться в сборке с непрерывной интеграцией или тому подобном. Конечно, это означает, что вы всегда используете одну и ту же сборку (которая содержит закрытые элементы). Если вы используете динамическую нагрузку и отражение, вам нравится играть с огнем, но вы всегда можете поймать исключение, которое может вызвать вызов.
- Смягчить медлительность отражения:
В последних версиях .Net Framework CreateDelegate в 50 раз превосходил вызов 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
вызовы будут примерно в 50 раз быстрее, чем MethodInfo.Invoke
использование draw
в качестве стандарта Func
:
var res = draw(methodParams);
Проверьте этот пост, чтобы увидеть эталонный тест по различным вызовам методов.