La reflexión especialmente sobre los miembros privados es incorrecta
- Reflexión rompe tipo seguridad. Puede intentar invocar un método que ya no existe (o con los parámetros incorrectos, o con demasiados parámetros, o no lo suficiente ... o incluso en el orden incorrecto (este es mi favorito :)). Por cierto, el tipo de retorno también podría cambiar.
- La reflexión es lenta.
La reflexión de miembros privados rompe el principio de encapsulación y, por lo tanto, expone su código a lo siguiente:
- Aumente la complejidad de su código porque tiene que manejar el comportamiento interno de las clases. Lo que está oculto debe permanecer oculto.
- Hace que su código sea fácil de romper ya que se compilará pero no se ejecutará si el método cambió su nombre.
- Hace que el código privado sea fácil de descifrar porque si es privado no está destinado a llamarse de esa manera. Tal vez el método privado espera algún estado interno antes de ser llamado.
¿Qué pasa si debo hacerlo de todos modos?
Hay casos en los que, cuando depende de un tercero o necesita alguna API no expuesta, debe reflexionar. Algunos también lo usan para probar algunas clases que poseen pero que no quieren cambiar la interfaz para dar acceso a los miembros internos solo para las pruebas.
Si lo haces, hazlo bien
- Mitigar lo fácil de romper:
Para mitigar el problema fácil de romper, lo mejor es detectar cualquier ruptura potencial probando en pruebas unitarias que se ejecutarían en una compilación de integración continua o similar. Por supuesto, significa que siempre usa el mismo ensamblado (que contiene los miembros privados). Si usa una carga dinámica y una reflexión, le gusta jugar con fuego, pero siempre puede detectar la Excepción que puede producir la llamada.
- Mitigar la lentitud de la reflexión:
En las versiones recientes de .Net Framework, CreateDelegate supera en un factor 50 la invocación 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
las llamadas serán aproximadamente 50 veces más rápidas que el MethodInfo.Invoke
uso draw
como un estándar Func
como ese:
var res = draw(methodParams);
Consulte esta publicación mía para ver el punto de referencia sobre invocaciones de diferentes métodos