Pergunta

O que exatamente é a reflexão? Eu li o artigo da Wikipedia sobre este assunto e eu entendo que é uma espécie de meta-programação, onde o programa pode modificar-se em tempo de execução, mas o que isso significa? Em que tipo de situações é esta uma abordagem boa e quando é o melhor para usá-lo?

Foi útil?

Solução

A reflexão é uma instalação onde você pode consultar um objeto sobre seus atributos em tempo de execução. Por exemplo, Python, Java e .Net têm instalações onde você pode encontrar as variáveis ??de instância ou métodos de um objeto.

Um exemplo de uma aplicação para a reflexão é uma camada de mapeamento O / R. Alguns utilização reflexão para a construção de um objecto por quering suas propriedades em tempo de execução e dinamicamente preencher uma instância. Isso permite que você faça isso através de programação com base em metadados de algum tipo de dicionário de dados sem ter que recompilar o aplicativo.

Para tomar um exemplo simples, eu vou usar Python porque suas instalações reflexão são muito simples de usar e envolvem menos clichê do que as de Java ou .Net.

ActivePython 2.5.2.2 (ActiveState Software Inc.) based on
Python 2.5.2 (r252:60911, Mar 27 2008, 17:57:18) [MSC v.1310 32 bit (Intel)] on
win32
Type "help", "copyright", "credits" or "license" for more information.
>>> class foo:
...     def __init__(self):
...             self.x = 1
...
>>> xx = foo()      # Creates an object and runs the constructor
>>> xx.__dict__     # System metadata about the object
{'x': 1}
>>> a = xx.__dict__ # Now we manipulate the object through 
>>> a['y'] = 2      # its metadata ...
>>> print xx.y      # ... and suddenly it has a new instance variable
2                   
>>>

Agora, nós usamos reflexão básica para examinar as variáveis ??de instância de um objeto arbitrário. O __dict__ variável especial no pitão é uma propriedade do sistema de um objecto que tem uma tabela hash dos seus membros introduzidos pelo nome da variável (ou método). Temos reflexivamente examinou o objeto e utilizado as instalações de reflexão para artificialmente picar uma segunda variável de instância para ele, que pode então exibir invocando-a como uma variável de instância.

Note que este truque especial não funciona em Java ou .Net, como as variáveis ??de instância são fixos. O sistema tipo de línguas não permite novas variáveis ??de instância a ser adicionado em tempo de execução da maneira que 'pato' sistema de digitação python do faz. No entanto, você poderia ter reflexivamente atualizou o valor de uma variável de instância que foi declarado na definição do tipo.

Você também pode usar o reflexo para chamadas de método dinamicamente construir e realizar várias outras truques como instanciar um objeto com base em um parâmetro. Por exemplo, se você tivesse algum tipo de plugin de sistema baseado em que certas capacidades eram opcionais, você poderia usar a reflexão para consultar o plugin sobre quais serviços oferecidos (talvez consultando se determinadas interfaces foram implementadas) sem a necessidade de metadados explícita.

Muitas interfaces de linguagem dinâmica como OLE uso de automação reflexão como parte integrante da interface.

Outras dicas

Não é tanto modificar código em tempo de execução, mas examinar objetos e pedindo-lhes para executar código sem saber o seu tipo estaticamente.

Uma maneira simples de descrever seria "uma maneira um pouco doloroso de fazer uma comportam linguagem de tipagem estática dinamicamente."

Editar: Usos:

  • Configuração (por exemplo, tomar um arquivo XML que especifica os tipos e propriedades, em seguida, construir objetos apropriados)
  • (Testes de unidade que são identificados por nome ou atributos)
  • Teste
  • Serviços da Web (em .NET, pelo menos, um monte de reflexão é usado no mecanismo de serviço web core)
  • fiação evento automático - fornecem um método com um nome apropriado, por exemplo, SubmitButton_Click e ASP.NET irá anexar esse método como um manipulador para o evento SubmitButton do Click (se tiver autowiring ligado)

É uma boa idéia? Bem, só quando as alternativas são dolorosas. Eu prefiro tipagem estática quando não ficar no caminho - então você obtém muita bondade em tempo de compilação, e é mais rápido também. Mas quando você do precisa dele, reflexão permite fazer várias coisas que de outra forma não seria possível.

O primeiro bom exemplo que eu posso pensar em cima da minha cabeça é para quando você precisa para executar um conjunto de métodos em um determinado objeto sem saber em tempo de compilação que métodos existirá nele.

Faça unidade testar estruturas, por exemplo. A classe corredor de teste que é responsável por executar todos os testes de unidade não sabe de antemão o que você está indo para nomear seus métodos. Tudo o que sabe é que eles vão ser prefixado com "test" (ou no caso do Java 5, anotado com @Test). Então, quando é dada uma classe de teste, ele reflete sobre essa classe, a fim de obter uma lista de todos os métodos nele. Em seguida, ele itera através desses nomes de métodos como strings e chama esses métodos no objeto se eles começam com "teste". Isso não seria possível sem reflexão. E isso é apenas um exemplo.

Reflection tem sido útil para mim em pelo menos 1 projecto que posso pensar. Nós escrevemos um programa interno "Process Manager" que realiza uma série de processos de negócios-chave em determinados intervalos. O projeto está configurado de forma que o núcleo é realmente apenas um serviço de janelas com temporizador objetos que o fogo fora a cada 30 segundos ou assim e verificar se há trabalho a fazer.

O verdadeiro trabalho está sendo feito em uma biblioteca de classes (apropriadamente chamado de "WorkerLib"). Nós definir classes com métodos públicos que realizam determinadas tarefas (mover arquivos, a transferir dados para locais remotos, etc.) A idéia é que o serviço de núcleo pode chamar métodos da biblioteca trabalhador sem saber nada sobre os métodos que está chamando. Isso nos permite criar uma agenda no banco de dados de postos de trabalho, e até mesmo adicionar novos métodos para a biblioteca de classes sem ter que alterar o núcleo do sistema.

A idéia básica é que podemos usar reflexo no serviço de núcleo para executar métodos cujos nomes temos armazenados no banco de dados definir os horários. É muito arrumado na prática. O nosso serviço de núcleo é sólido e alças que executam os trabalhos, conforme necessário, enquanto a biblioteca trabalhador real pode ser ampliado e alterados conforme necessário, sem o núcleo mesmo carinho.

Se você precisar de mais explicações, por favor, não hesite em perguntar. Este foi simplesmente a melhor maneira que eu poderia pensar para explicar um cenário do mundo real onde a reflexão realmente torna as coisas mais fáceis para nós.

Outro exemplo: Eu tenho o código que eu uso que leva a saída de um banco de dados - que é um conjunto de linhas com colunas nomeadas - e alimenta-lo em uma matriz de objetos. Eu iterar através das linhas, e se o objeto de destino tem uma propriedade com o mesmo nome e tipo, eu defini-lo. Isto faz para o meu código-obtenção de dados só de olhar algo como isto:

SqlDataReader sdr = Helper.GetReader("GetClientByID", ClientID);
Client c = new Client();
FillObject(sdr, c);
return c;

Realmente, a reflexão deve ser pensado como uma espécie de amplificador para o código. Ele pode fazer um bom código melhor e mais limpo, e código ruim pior. O que isso faz? É realmente permite que você escrever o código, que a sua não totalmente certo o que ele vai fazer no momento de escrevê-lo. Você tem uma idéia geral, mas ele permite que você não o código que objetos, métodos e propriedades estão indo executar quando o programa é compilado.

Outras mensagens estão corretos quando dizem que permite que o programa para executar código com base em valores de configuração, mas é o poder real é que ele permite que você dobre severamente as regras de programação orientada a objeto. Isso é realmente o que faz. É uma espécie de como transformar as medidas de segurança off. métodos privados e propriedades podem ser acessadas através da reflexão, juntamente com qualquer outra coisa.

Um excelente exemplo de quando o MS utiliza reflexão é com a ligao de dados no objecto de dados. Você especifica o nome do campo de texto e campo de dados para um objeto para se ligam a uma lista suspensa etc. para baixo, e o código reflete o objeto e tira as informações apropriadas. O objeto vinculação de dados faz o mesmo processo uma e outra vez, mas ele não sabe que tipo de objeto que tem que ligar com. A reflexão é uma maneira conveniente de escrever um pouco de código para lidar com todos os casos possíveis.

Em Java é basicamente uma forma de instanciar uma classe sem saber sobre ele antes da mão. Digamos que você queira que o usuário seja capaz de alterar um arquivo de configuração, adicionando a classe eles querem o seu programa para o uso (digamos que você tem inúmeras implementações de alguns interface). Com reflexão você pode criar um objeto com base em apenas isso do nome, assinatura do método, etc.. . e depois lançá-lo à sua interface.

reflexão é útil para a configuração de tempo de execução, permitindo que as peças de um sistema a ser accionado por meio da configuração externa.

Por exemplo, uma fábrica de classes poderia construir tipos concretos diferentes com base em um arquivo de entrada, onde os tipos de concreto requer informações de configuração diferente para chamar um construtor de concreto ao invés de usar uma interface builder. (O método do construtor do objecto a ser localizado utilizando reflexão).

A reflexão é (basicamente) a capacidade de um programa de consulta para informações de tipo que estava disponível para o compilador. Assim, por exemplo, recebeu o nome de um tipo que você pode consultar os métodos que ele contém. Então, para cada método que você pode consultar os tipos dos parâmetros que tomam etc etc etc.

É útil para a configuração de tempo de execução, onde você tem um arquivo de configuração que especifica o comportamento do seu aplicativo. A configuração pode conter os nomes dos tipos de concreto que você deve usar (como é frequentemente o caso com os recipientes COI). Usando reflexão você pode criar uma instância desse tipo concreto (através de uma API de reflexão) e usá-lo.

Vou te dar um exemplo.

Como um exercício de programação eu escrevi um verificador de arquivo de mp3. Faz a varredura de minha biblioteca de música e exibe o id1 / ID2 etiquetas Estou interessado em em um DataGridView. I usar a reflexão para obter as propriedades da classe informações mp3 sem o código UI ter que saber qualquer coisa sobre essa classe. Se eu quiser alterar as informações que recebe exibido I pode editar a informação mp3 classe ou alterar sua configuração (dependendo de como eu escrevi a classe) e não tem que atualizar a interface do usuário.

também significou que eu fui capaz de usar Dependency Injection para usar a mesma de ponta a informação do mostrador sobre fotografias digitais apenas trocando a classe biblioteca de dados.

Assembléias contém os módulos, os módulos contêm tipos e tipos contêm membros. Reflexão proporciona objectos que os conjuntos de encapsular, os módulos, e tipos. Você pode usar a reflexão para criar dinamicamente uma instância de um tipo, ligar o tipo a um objeto existente, ou obter o tipo de um objeto existente. Em seguida, você pode chamar os métodos do tipo ou acessar seus campos e propriedades. Os usos típicos de reflexão incluem o seguinte:

  • Uso montagem para definir e conjuntos de carga, os módulos de carga que estão listados no manifesto montagem, e localizar um tipo a partir deste conjunto e criar uma instância do mesmo.
  • Use Module para descobrir informações como o assembly que contém o módulo e as classes no módulo. Você também pode obter todos os métodos globais ou outros específicos, métodos não globais definidos no módulo.
  • Use ConstructorInfo para descobrir informações como o nome, parâmetros, modificadores de acesso (como pública ou privada), e detalhes de implementação (tais como abstrato ou virtual) de um construtor. Use as GetConstructors ou método GetConstructor de um tipo para invocar um construtor específico.
  • Use MethodInfo para descobrir informações como o nome, tipo de retorno, parâmetros, modificadores de acesso (como pública ou privada), e detalhes de implementação (tais como abstrato ou virtual) de um método. Use as GetMethods ou método GetMethod de um tipo para chamar um método específico.
  • Use FieldInfo para descobrir informações como o nome, modificadores de acesso (como pública ou privada) e detalhes de implementação (tais como estática) de um campo, e para obter ou valores de campos definidos.
  • Use EventInfo para descobrir informações como o nome, tipo de dados manipulador de eventos, atributos personalizados, tipo declarativo, e tipo refletida de um evento, e para adicionar ou remover manipuladores de eventos.
  • Use PropertyInfo para descobrir informações como o nome, tipo de dados, tipo declarativo, tipo refletida, e somente leitura ou gravável status de uma propriedade, e para obter ou valores conjunto de propriedades.
  • Use ParameterInfo para descobrir informações como o tipo de nome, os dados de um parâmetro, se um parâmetro é uma entrada ou parâmetro de saída e a posição do parâmetro em uma assinatura do método.
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top