A reflexão especialmente sobre membros privados está errada
- A reflexão quebra o tipo de segurança. Você pode tentar invocar um método que não existe (mais), ou com os parâmetros errados, ou com muitos parâmetros, ou insuficientes ... ou até na ordem errada (este é o meu favorito :)). A propósito, o tipo de retorno também pode mudar.
- A reflexão é lenta.
A reflexão de membros privados quebra o princípio do encapsulamento e, portanto, expõe seu código ao seguinte:
- Aumente a complexidade do seu código, pois ele precisa lidar com o comportamento interno das classes. O que está oculto deve permanecer oculto.
- Facilita a quebra do seu código, pois ele será compilado, mas não será executado se o método mudar de nome.
- Facilita a quebra do código privado, porque, se for privado, não se destina a ser chamado dessa maneira. Talvez o método privado espere algum estado interno antes de ser chamado.
E se eu devo fazê-lo de qualquer maneira?
Há casos em que, quando você depende de terceiros ou precisa de uma API não exposta, é necessário refletir um pouco. Alguns também o usam para testar algumas classes que possuem, mas não desejam alterar a interface para dar acesso aos membros internos apenas para testes.
Se você fizer, faça certo
- Mitigue o fácil de quebrar:
Para atenuar o problema fácil de quebrar, o melhor é detectar qualquer possível quebra testando em testes de unidade que seriam executados em uma construção de integração contínua ou algo assim. Obviamente, isso significa que você sempre usa a mesma montagem (que contém os membros privados). Se você usa uma carga e reflexão dinâmicas, gosta de brincar com fogo, mas sempre pode capturar a exceção que a chamada pode produzir.
- Mitigue a lentidão da reflexão:
Nas versões recentes do .Net Framework, o CreateDelegate supera um fator 50 que o MethodInfo chama:
// 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
as chamadas serão 50 vezes mais rápidas do que as MethodInfo.Invoke
usadas draw
como padrão Func
:
var res = draw(methodParams);
Verifique esta publicação minha para ver referências em diferentes invocações de métodos