Este artigo foi traduzido por máquina.

O programador

Multiparadigmatic.NET, parte 6: Refletivo Metaprogramming

Ted Neward

A maratona continua. No meu edição anterior discutimos automático metaprogramming e por este ponto, as idéias de aspectos comuns e variabilidade devem ser levando em um familiar. Estou agora full-em falar sobre metaprogramming — a idéia de gravar programas de programas.

No mês passado examinei uma das abordagens mais familiares para metaprogramming: automático metaprogramming, mais conhecido como geração de código. Em um cenário de metaprogramming automático, os desenvolvedores escrevem programas que descrevem as "coisas" seja gerado. Geralmente isso é feito com o auxílio de parâmetros de linha de comando ou outras informações, como esquemas de banco de dados relacionais, arquivos XSD ou mesmo os documentos WSDL (Web Services Description Language).

Porque a geração de código é essencialmente "como se" o código foram escritas por intervenção humana, variabilidade pode vir em qualquer ponto dentro do código. Tipos de dados, métodos, herança... tudo isso pode variar de acordo com a necessidade. A desvantagem, é claro, a dupla. Em primeiro lugar, há muita variabilidade pode processar o código gerado (e, mais freqüentemente que não, os modelos por meio do qual o código é gerado) difícil de entender. Segundo, os artefatos gerados são essencialmente não editáveis, a menos que a geração de código é particionada away alguma forma através do uso de classes parciais ou geração de código não é mais necessária.

Felizmente, TRANSLATION FROM VPE FOR CSHARP e o Visual Basic oferecem mais metaprogrammatic táticas que apenas automática metaprogramming e tiverem feito isso desde os primeiros dias do Microsoft.NET Framework.

Problemas persistentes

Um problema recorrente no ambiente orientado a objeto é o de persistência de objeto para relacional — também conhecido como conversão de objeto para XML ou no mundo Web 2. 0 mais moderno, a transformação de objeto para JSON. Apesar dos esforços dos desenvolvedores, parece inevitável que precisam de modelos de objeto para escapar do CLR de alguma forma e mover pela rede ou mover para o disco e vice-versa. E aqui está o problema: os modos anteriores do projeto — e de procedimento e orientada a objeto — não oferecem soluções adequadas para esse dilema.

Considere uma representação simplificada canônica de um ser humano modelado no código:

classe pessoa {public string FirstName {get;conjunto;}
 string pública LastName {get;conjunto;}
 pública int idade {get;conjunto;}

  Pessoa pública (string fn, ln string, int uma)
 {FirstName = fn;LastName = ln;Idade = um;} }

Persisting instâncias desse objeto, como na verdade, não é difícil, principalmente porque as propriedades (em sua forma mais simples) correspondem em uma base individual com as colunas de uma tabela relacional e as propriedades são acessíveis publicamente. Você poderia escrever um procedimento para levar as instâncias da pessoa, extrair os bits de dados, injetar esses bits em instruções SQL e enviar a instrução resultante no banco de dados:

DB de classe {bool estático público Insert (pessoa p)
 {/ / obter conexão (não mostrado) / / 
seqüência de caracteres SQL construir SQL = "Inserir em pessoa valores 
("+ "'"+ p.FirstName + "',"+ "'"+ p + "',"+ p.Age + ")";/ / 
Enviar SQL resultante para o banco de dados (não mostrado) 
/ / retornar êxito ou falha de retorno true;} }

A desvantagem de uma abordagem de procedimentos rears a cabeça feio rapidamente: novos tipos (animal de estimação, instrutor, estudantes e assim por diante) que também deseja que seja inserido exigirá novos métodos de principalmente o código semelhante. Pior ainda, se as propriedades expostas à API pública não correspondem-para-um com colunas ou campos internos, coisas podem acabar rapidamente — os desenvolvedores que criam as rotinas SQL precisará saber quais campos precisam de persistência e quais não, uma violação bastante clara de encapsulamento.

Da perspectiva do design, o problema de objeto relacional deseja capturar as partes esque SQL de persistência de dados em uso comum, para que o gerenciamento de conexões de banco de dados e transações é tratado em um único lugar, mas ainda permite a variabilidade na estrutura real dos itens que sejam persistentes (ou recuperados).

Lembre-se, de nossas investigações anteriores, que abordagens procedimentos capturar semelhança algorítmica e essa herança captura semelhança estrutural permitindo variabilidade (positiva) ao mesmo tempo — mas nenhum deles faça exatamente o que é necessário. A abordagem de herança — colocando as características comuns em uma classe base — irá exigir que os desenvolvedores que trabalham em classes derivadas Especifica a seqüência de caracteres SQL e lidar com grande parte de escrituração contábil de entrada/saída (essencialmente apertando a semelhança volta em classes derivadas). A abordagem de procedimentos terá algum tipo de variabilidade (extração e criação de SQL para executar) do procedimento especificado de fora do procedimento, o que acaba por ser relativamente difícil de alcançar.

Digite Metaprogramming

Uma solução para o problema de persistência de objeto relacional citado com freqüência é que automático metaprogramming: usando o esquema de banco de dados, criar classes que sabe como persistir próprios para e do banco de dados.

Infelizmente, isso tem todos os problemas tradicionais de geração de código, especialmente quando classes deseja alterar a representação de objeto para algo mais fácil trabalhar com que o que implica o esquema de banco de dados físico. Por exemplo, uma coluna VARCHAR(2000) seria muito mais fácil trabalhar com se fosse um.NET Framework System. String e não um char [2000].

Outras técnicas de geração de código começou a definições de classe e criou um esquema de banco de dados juntamente com as definições de classe persistente … mas isso significava que alguma forma agora a hierarquia de objeto foi duplicada em dois modelos diferentes, unicamente para persistência e outra para todo o resto. (Observe que, assim que for necessário transformar o objeto em XML, outra hierarquia springs em sendo que você precise tratar e outra para lidar com JSON. Rapidamente essa abordagem cresce intractable.)

Felizmente, Refletivo metaprogramming oferece alívio possível. Uma parte da.NET Framework desde 1. 0, System. Reflection permite aos desenvolvedores examinar a estrutura de objetos em tempo de execução, que nesse caso permite que a infra-estrutura preocupados com persistência a oportunidade de examinar a estrutura do objeto sejam persistente e gerar o SQL necessária a partir daí. Uma introdução básica ao System. Reflection está bem documentada ambos em documentação do MSDN em MSDN.microsoft.com/library/f7ykdhsy(v=vs.400) e, no msdn Magazine artigos "reflexão de uso para descobrir e avaliar os tipos mais comuns na.NET Framework"(MSDN.microsoft.com/magazine/cc188926) e "tudo sobre CLR: reflexões sobre a reflexão" (MSDN.microsoft.com/magazine/cc163408). Não irei discutir qualquer ainda mais aqui.

Reflexão permite a semelhança de algoritmo, permitindo o variabilidade da estrutura manipulada por esse algoritmo, tudo sem deixar de preservar a aparência de encapsulamento. Como reflexão (em um contexto de segurança configurados adequadamente) tem acesso a membros privados de objetos, os dados internos ainda podem ser manipulados sem forçar os membros de dados para se tornar pública. Variabilidade positiva — a capacidade de variar adicionando coisas — é, como sempre, fácil de trabalhar, como o número de campos é totalmente irrelevante para a maioria dos códigos à base de reflexão. Negativo variabilidade — a capacidade de variar, removendo as coisas — parece não caber, entretanto. Afinal, uma classe sem campos não precisa ser persistentes, não é mesmo? E uma infra-estrutura baseada em reflexão loop pelos campos particulares não têm grande parte de um problema não looping todo, como não fizer sentido, como o que pode parecer.

No entanto, aqui a variabilidade negativa é ligeiramente diferente do que simplesmente não ter campos. Em determinados cenários, a classe Person terá campos internos que não deseja que sejam mantidas em todos os. Ou, mais strikingly, a classe Person terá campos quer persistente em um formato de dados diferente de sua representação de host do CLR. Person.BirthDate quer que sejam armazenadas como uma seqüência de caracteres, talvez, ou mesmo através de três colunas (dia, mês ou ano) em vez de em uma única coluna. Em outras palavras, a variabilidade negativa em um sentido metaprogrammatic reflexivo é não sobre a falta de campos, mas sobre como fazer algo diferente de determinadas instâncias de tipos que seriam tratados de forma padrão (uma seqüência de caracteres para uma coluna VARCHAR, sendo o padrão de persistênciaPor exemplo, mas para um ou mais campos específicos, uma seqüência de caracteres para uma coluna BLOB de persistência).

A.NET Framework faz uso de atributos personalizados para transmitir essa variação negativa. Os desenvolvedores usam atributos de elementos de marca dentro da classe para transmitir o desejo de que o tratamento personalizado, como, por exemplo, @ NotSerialized no caso de serialização do objeto. É importante observar, entretanto, o atributo propriamente dito não faz nada — ele é meramente um sinalizador no código procurando esse atributo. Por si só, em seguida, o atributo não fornece nenhuma variabilidade negativa, mas simplesmente torna mais fácil indicar quando essa variabilidade negativa deve participar.

Atributos também podem ser usados para transmitir a variabilidade positiva. Um exemplo é como o.NET Framework usa atributos para transmitir o tratamento transacional, supondo que a falta de um atributo em um método indica sem qualquer tipo de afinidade transacional.

Espelho, espelho na parede

Sem atributos, refletivas metaprogramming estabelece um totalmente novo tipo de variabilidade. Agora nomes de pode ser usado para referir-se elementos dentro do programa (em vez de por meio de símbolos do compilador) — e muito posteriormente (runtime) que o compilador permite que tradicionalmente. Por exemplo, descartes antecipados do framework de teste de unidade NUnit, como seu primo JUnit no espaço de Java, usado reflexão para descobrir os métodos que começaram com "test" como parte do nome e, em seguida, pressupõe-se de que eles eram os métodos de teste para ser executado como parte de um conjunto de teste.

A abordagem baseada em nome requer que os desenvolvedores tirem elementos tradicionalmente reservados para o olho humano — os nomes das coisas — e exigem que eles seguem convenções rígidas, como, por exemplo, o prefixo "test" para métodos NUnit. O uso de atributos personalizados libera a convenção de nomenclatura com (às custas de agora necessitando de construções de código adicional nas classes em questão), criando essencialmente um mecanismo de opt-in que os desenvolvedores deve aceitar para receber os benefícios da metaprogram.

Os atributos também fornecem a capacidade de dados arbitrários de marca junto com o atributo, fornecendo uma parametrização muito mais granular do comportamento metaprogrammatic. Isso é algo que normalmente não é possível com automático metaprogramming, especialmente quando o cliente quer um comportamento diferente para estruturalmente semelhante constrói (como, por exemplo, o exemplo strings-to-BLOBs-instead-of-VARCHAR-columns anteriores).

No entanto, devido à sua natureza de limite de tempo de execução, reflexão impõe com freqüência um impacto no código que utiliza extensivamente no desempenho. Além disso, a reflexão não oferece soluções para os problemas citados no cenário metaprogramming automático desde o último mês — a proliferação de classes, por exemplo. Outra solução de metaprogrammatic está disponível, mas que terá que aguardar o próximo mês.

Boa codificação!

Ted Neward é uma entidade de segurança com Neward &Associa uma firma independente especializado em enterprise.NET Framework e Java sistemas da plataforma. Ele escreveu mais de 100 artigos, é um palestrante INETA e de TRANSLATION FROM VPE FOR CSHARP MVP e autor e co-autor de doze livros, incluindo "Profissional F # 2. 0" (Wrox 2010). Ele também oferece consultoria e mentors regularmente. Entrar no ted@tedneward.com com perguntas ou solicitações de consultoria e ler seu blog em blogs.tedneward.com.

Graças ao especialista técnico seguir pela revisão deste artigo: Anthony verde