Não sei por que, mas sempre sinto que estou "trapaceando" quando uso a reflexão - talvez seja por causa do desempenho que sei que estou sofrendo.
Parte de mim diz que, se faz parte do idioma que você está usando e pode realizar o que está tentando fazer, por que não usá-lo? A outra parte de mim diz que deve haver uma maneira de fazer isso sem usar a reflexão. Eu acho que talvez dependa da situação.
Quais são os possíveis problemas que preciso observar ao usar a reflexão e qual a minha preocupação com eles? Quanto esforço vale a pena tentar encontrar uma solução mais convencional?
Respostas:
Não, não é trapaça - é uma maneira de resolver problemas em algumas linguagens de programação.
Agora, muitas vezes não é a melhor solução (mais limpa, mais simples, mais fácil de manter). Se houver uma maneira melhor, use essa de fato. No entanto, às vezes não há. Ou, se houver, é muito mais complexo, envolvendo muita duplicação de código etc., o que torna inviável (difícil de manter a longo prazo).
Dois exemplos de nosso projeto atual (Java):
fieldX
para o campo apropriado na classe e para inicializar o último. Em alguns casos, ele pode criar uma caixa de diálogo GUI simples a partir das propriedades identificadas em tempo real. Sem reflexão, isso levaria centenas de linhas de código em vários aplicativos. Portanto, a reflexão nos ajudou a montar uma ferramenta simples rapidamente, sem muito barulho, e nos permitiu focar na parte importante (regressão testando nosso aplicativo da web, analisando os logs do servidor etc.) e não no irrelevante.A linha inferior é, como qualquer ferramenta poderosa, a reflexão também pode ser usada para dar um tiro no próprio pé. Se você aprender quando e como (não) usá-lo, poderá oferecer soluções elegantes e limpas para problemas difíceis. Se você abusar, pode transformar um problema simples em uma bagunça complexa e feia.
fonte
if (propName = n) setN(propValue);
, você pode nomear suas tags XML (ou seja) iguais às suas propriedades de código e executar um loop sobre elas. Esse método também facilita muito a adição de propriedades posteriormente.Não é trapaça. Mas geralmente é uma má ideia no código de produção pelo menos pelos seguintes motivos:
Sugiro limitar o uso da reflexão aos seguintes casos:
Em todos os outros casos, sugiro descobrir uma abordagem que evite a reflexão. Definir uma interface com o (s) método (s) apropriado (s) e implementá-lo no conjunto de classes para o qual você deseja chamar o (s) método (s) geralmente é suficiente para resolver os casos mais simples.
fonte
A reflexão é apenas outra forma de metaprogramação e tão válida quanto os parâmetros baseados em tipo que você vê na maioria dos idiomas atualmente. A reflexão é poderosa e genérica, e os programas reflexivos são de alta ordem para manutenção (quando usados corretamente, é claro) e muito mais do que programas puramente orientados a objetos ou procedimentais. Sim, você paga um preço de desempenho - mas eu ficaria feliz em optar por um programa mais lento que seja mais sustentável em muitos, ou mesmo na maioria dos casos.
fonte
Certamente tudo depende do que você está tentando alcançar.
Por exemplo, escrevi um aplicativo de verificação de mídia que usa injeção de dependência para determinar que tipo de mídia (arquivos MP3 ou JPEG) verificar. O shell precisava exibir uma grade contendo as informações pertinentes para cada tipo, mas não tinha conhecimento do que iria exibir. Isso é definido na montagem que lê esse tipo de mídia.
Portanto, tive que usar a reflexão para obter o número de colunas a serem exibidas e seus tipos e nomes para poder configurar a grade corretamente. Isso também significava que eu poderia atualizar a biblioteca injetada (ou criar uma nova) sem alterar nenhum outro código ou arquivo de configuração.
A única outra maneira seria ter um arquivo de configuração que precisaria ser atualizado quando eu alternasse o tipo de mídia que está sendo verificado. Isso teria introduzido outro ponto de falha para o aplicativo.
fonte
O Reflection é uma ferramenta incrível se você é um autor de biblioteca e, portanto, não tem influência sobre os dados recebidos. Uma combinação de reflexão e metaprogramação pode permitir que sua biblioteca funcione perfeitamente com chamadores arbitrários, sem que eles precisem passar por obstáculos de geração de código etc.
Eu tento desencorajar a reflexão no código do aplicativo ; na camada de aplicativo, você deve usar diferentes metáforas - interfaces, abstração, encapsulamento etc.
fonte
A reflexão é fantástica para criar ferramentas para desenvolvedores.
Como permite que seu ambiente de construção inspecione o código e gere potencialmente as ferramentas corretas para manipular / init inspeciona o código.
Como técnica de programação geral, pode ser útil, mas é mais frágil do que a maioria das pessoas imagina.
Um uso realmente de desenvolvimento para reflexão (IMO) é que a escrita de uma biblioteca de streaming genérica é muito simples (desde que a descrição da sua classe nunca seja alterada (ela se tornará uma solução muito quebradiça)).
fonte
O uso da reflexão é frequentemente prejudicial nas línguas OO, se não for usado com grande consciência.
Perdi a conta de quantas perguntas ruins já vi nos sites StackExchange onde
Aqui estão exemplos típicos.
A maior parte do objetivo do OO é que
Se, em qualquer ponto do seu código, o ponto 2 não for válido para um objeto ao qual você passou, um ou mais deles será verdadeiro
Desenvolvedores pouco qualificados simplesmente não entendem isso e acreditam que podem receber qualquer coisa em qualquer parte de seu código e fazem o que desejam de um conjunto de possibilidades (codificado). Esses idiotas usam muito a reflexão .
Para linguagens OO, a reflexão deve ser necessária apenas na meta atividade (carregadores de classes, injeção de dependência, etc.). Nesses contextos, a reflexão é necessária porque você está fornecendo um serviço genérico para auxiliar na manipulação / configuração do código sobre o qual você não sabe nada por um motivo bom e legítimo. Em quase qualquer outra situação, se você está buscando reflexão, está fazendo algo errado e precisa se perguntar por que esse pedaço de código não sabe o suficiente sobre o objeto que foi passado para ele.
fonte
Uma alternativa, nos casos em que o domínio das classes refletidas é bem definido, é usar a reflexão junto com outros metadados para gerar código , em vez de usar a reflexão no tempo de execução. Eu faço isso usando o FreeMarker / FMPP; existem muitas outras ferramentas para você escolher. A vantagem disso é que você acaba com um código "real" que pode ser facilmente depurado etc.
Dependendo da situação, isso pode ajudá-lo a tornar um código muito mais rápido - ou apenas um monte de código inchar. Evita as desvantagens da reflexão:
mencionado anteriormente.
Se a reflexão parecer trapaça, pode ser porque você a baseia em muitas suposições, das quais não tem certeza, e seu intestino está avisando que isso é arriscado. Certifique-se de fornecer uma maneira de aprimorar os metadados inerentes à reflexão com seus próprios metadados, onde você pode descrever todas as peculiaridades e casos especiais das classes do mundo real que você pode encontrar.
fonte
Não é trapaça, mas, como qualquer ferramenta, deve ser usada para o que se destina a resolver. Reflexão, por definição, permite que você inspecione e modifique o código através do código; se é isso que você precisa fazer, a reflexão é a ferramenta para o trabalho. Reflexão é tudo sobre meta-código: código que segmenta código (em oposição ao código regular, que segmenta dados).
Um exemplo de bom uso de reflexão são as classes genéricas da interface de serviço da web: Um design típico é separar a implementação do protocolo da funcionalidade da carga útil. Então você tem uma classe (vamos chamá-la
T
) que implementa sua carga útil e outra que implementa o protocolo (P
).T
é bastante direto: para cada chamada que você deseja fazer, basta escrever um método que faça o que deve ser feito.P
, no entanto, precisa mapear chamadas de serviço da web para chamadas de método. Tornar esse mapeamento genérico é desejável, pois evita redundância e tornaP
altamente reutilizável. O Reflection fornece os meios para inspecionar a classeT
em tempo de execução e chamar seus métodos com base nas seqüências de caracteres transmitidasP
pelo protocolo de serviço da web, sem nenhum conhecimento da classe em tempo de compilaçãoT
. Usando a regra 'código sobre código', pode-se argumentar que a classeP
possui o código na classeT
como parte de seus dados.Contudo.
O Reflection também oferece ferramentas para contornar as restrições do sistema de tipos da linguagem - teoricamente, você pode passar todos os parâmetros como tipo
object
e chamar seus métodos através de reflexões. Voilà, a linguagem que deveria impor uma forte disciplina estática de digitação agora se comporta como uma linguagem dinamicamente digitada com ligação tardia, apenas que a sintaxe é muito mais elaborada. Todas as instâncias desse padrão que eu vi até agora foram um hack sujo e, invariavelmente, uma solução dentro do sistema de tipos da linguagem seria possível e seria mais segura, elegante e eficiente em todos os aspectos .Existem algumas exceções, como controles da GUI que podem ser vinculados a dados para vários tipos não relacionados de fontes de dados; determinar que seus dados implementem uma determinada interface apenas para que você possa vinculá-los a dados não é realista e o programador não deve implementar um adaptador para cada tipo de fonte de dados. Nesse caso, usar a reflexão para detectar o tipo de fonte de dados e ajustar a ligação de dados é uma opção mais útil.
fonte
Um problema que tivemos com o Reflection foi quando adicionamos Ofuscação à mistura. Todas as classes recebem novos nomes e o carregamento repentino de uma classe ou função por seu nome para de funcionar.
fonte
Depende totalmente. Um exemplo de algo que seria difícil de fazer sem reflexão seria replicar ObjectListView . Também gera código IL em tempo real.
fonte
A reflexão é o principal método de criação de sistemas baseados em convenções. Eu não ficaria surpreso ao descobrir que ele está sendo muito utilizado na maioria das estruturas MVC. É um componente importante nos ORMs. Provavelmente, você já está usando componentes criados com ele todos os dias.
A alternativa para esse uso é a configuração, que possui seu próprio conjunto de desvantagens.
fonte
A reflexão pode alcançar coisas que simplesmente não podem ser feitas praticamente de outra maneira.
Por exemplo, considere como otimizar este código:
Há um teste caro no meio do loop interno, mas extraí-lo requer que você reescreva o loop uma vez para cada operador. A reflexão nos permite obter desempenho igual ao extrair esse teste, sem repetir o loop uma dúzia de vezes (e, assim, sacrificar a manutenção). Basta gerar e compilar o loop que você precisa em tempo real.
Na verdade, eu fiz essa otimização , embora a situação fosse um pouco mais complicada e os resultados foram surpreendentes. Uma melhoria de ordem de magnitude no desempenho e menos linhas de código.
(Nota: inicialmente, tentei o equivalente a passar um Func em vez de um caractere, e foi um pouco melhor, mas não quase o reflexo de 10x obtido.)
fonte
De jeito nenhum ele está trapaceando ... Em vez disso, ele permite que os servidores de aplicativos executem as classes criadas pelo usuário com o nome de sua escolha, fornecendo flexibilidade ao usuário e não trapaceando.
E se você quiser ver o código de qualquer arquivo .class (em Java), existem vários descompiladores disponíveis gratuitamente!
fonte