Como a injeção de dependência pode ser integrada ao idioma? [fechadas]

10

Eu estive pensando um pouco sobre como a injeção de dependência poderia ser melhor integrada diretamente em uma linguagem do tipo C #. Encontrei uma solução em potencial sobre a qual gostaria de ouvir sua opinião. Eu não usei muitas estruturas de injeção de dependência, então pode haver algo que estou ignorando

De qualquer forma, a ideia é poder declarar propriedades como "injetáveis" usando uma palavra-chave. Quando um objeto é instanciado e essa propriedade não é inicializada por meio do construtor ou inicializador de objetos, ele solicita uma instância desse tipo de propriedade de algum serviço global.

Da mesma forma, você registra manipuladores para diferentes tipos nesse serviço, para poder instanciar o tipo de propriedade injetada.

A vantagem de usar esse tipo de arquitetura IMO é que ela é bastante flexível e fácil de usar. A desvantagem é que pode haver alguma sobrecarga de fazer a chamada para o singleton toda vez que você inicia uma classe que tem injeção.

Por outro lado, isso é apenas um problema para as classes instanciadas com freqüência em uma solução de alto desempenho, portanto não deve ser um problema. Talvez você possa usar algum tipo de fábrica nesses casos.

Pensamentos, questões, perguntas, melhores idéias?

Código

public class SomeClass
{

  public SomeClass()
  {
     //implicit behavior if Animal is not set in constructor or initializer
    this.Animal =  GlobalInjector.Get(this,typeof(Mammal))

  }

  public injectable Mammal Animal  
  {
   get;
   set;
  }
}


 GlobalInjector.Register(typeof(Mammal), () => return new Mammal(someParameter));
Homde
fonte
Você poderia dar um exemplo de pseudo-código para nós que não conhece o DI? PS. Talvez você possa responder minha pergunta sobre DI também? :)
Steven
2
Não tenho certeza se entendi. Você pode obter tudo isso com um contêiner DI global e um atributo '[Injetável]' em vez de uma palavra-chave, certo?
Nikie
Oi, eu tentei escrever um pouco sobre DI em sua pergunta, não tenho certeza ele responde-lo embora
Homde
Nikie: Sim, claro, eu acho que você poderia implementar o mecanismo real de maneiras diferentes, eu estou mais interessado se a lógica subjacente é som
Homde
Então, o que há de diferente entre este e o IoC existente, além da palavra-chave extra?
Matthew Whited 30/03

Respostas:

7

Há coisas que pertencem às línguas e outras que não. Há muito tempo, a C reconheceu que o IO não pertencia à linguagem porque é externo ao modelo de computação e pode ser implementado com bibliotecas de funções.

Injeção de dependência é assim. É externo à linguagem e pode ser implementado com estruturas apropriadas.

Um dos problemas com as linguagens modernas é que elas tentam fazer demais. Eventualmente, essas linguagens entram em colapso devido ao seu próprio peso, à medida que os programadores fogem para linguagens mais simples.

Tio Bob.
fonte
Concordo, em teoria, que você não pode ter uma linguagem em que cada função seja uma característica da linguagem sem que ela seja inchada. No entanto, sempre há espaço para novas abstrações mais altas que nos ajudam a escrever um código melhor. Talvez a injeção de dependência em si não seja o problema que precisa ser resolvido, mas o problema que ele resolve, ou seja, uma maneira de facilitar a redução de dependências. Isto pode não ser a melhor maneira de fazê-lo embora :)
Homde
5

Não é necessário

Uma das coisas que eu mais gosto nas melhores estruturas de DI que eu usei é que o código de configuração de nível superior é a única parte do seu código que precisa saber sobre a DI. A fiação automática é feita no nível do contêiner e da configuração / "carregamento do módulo", e o código do aplicativo pode ficar completamente inconsciente.

Isso significa que não há atributos, nem cordas mágicas, nem convenções. Cada parte do código sabe apenas que aceita código em seu construtor (/ properties / methods), e isso é tudo.

Com um design como esse, você não precisa alterar o idioma para oferecer suporte à injeção de dependência.

É potencialmente perigoso

O que mais temo em um sistema de injeção de dependência integrado ao idioma é que ele criaria uma barreira contra qualquer outra implementação, mas provavelmente se colocaria em um canto em algum aspecto.

Algumas maneiras de pintar a si mesmo em um canto:

  • Apenas suportando configuração baseada em XML ou apenas configuração baseada em código
  • Não ser capaz de suportar de maneira limpa o padrão de design da fábrica (não apenas componentes transitórios: componentes gerados em tempo de execução)
  • De alguma forma, alterando meu código, fui forçado a usar injeção de dependência e não pude simplesmente instanciar minha classe para testes de unidade
  • Não suporta ciclos de vida personalizados
  • Não sendo extensível
  • Não sendo substituível nos casos em que preciso de maior personalização
  • Sendo quebrado de alguma maneira que ainda não entendemos, porque os usuários de .net não usam o DI há tempo suficiente para conhecer as armadilhas
Merlyn Morgan-Graham
fonte
4

Você já viu o Managed Extensibility Framework que acompanha o .NET 4? Aqui está um artigo que escrevi com alguns exemplos. Basicamente, é uma forma de injeção de dependência incorporada ao .NET, com os recursos adicionais de descoberta em tempo de execução.

As injeções de propriedades são assim:

class Program
{
    [Import]
    public IMessageSender MessageSender { get; set; }
}

As injeções do construtor são assim:

class Program
{
    [ImportingConstructor]
    public Program(IMessageSender messageSender) 
    {
    ...
    }
}

Você pode importar campos, fazer a importação opcional, importar coleções de serviços, incluindo a importação lenta com metadados, para poder procurar um serviço apropriado para instanciar. Você pode até reimportar em tempo de execução para procurar novas extensões.

Scott Whitlock
fonte
Enquanto MEF é muito legal para o material plug-in Eu não acho que eu gostaria de usá-lo como um mecanismo DI geral
Homde
11
@MKO - Você pode elaborar o que está faltando? Estou ciente de todos os artigos em que Glenn Block corre para garantir às pessoas que o MEF não está disposto a substituir todas as estruturas de DI, mas se você olhar para os detalhes, é óbvio que é mais uma declaração política do que qualquer outra coisa. No entanto, se você puder fornecer uma boa lista de recursos que o MEF não possui em comparação com outras estruturas de DI, isso ajudará as pessoas a tomar uma decisão informada. Além disso, a questão é sobre estruturas de DI em C #, e o MEF é claramente um contêiner de DI na estrutura .NET.
Scott Whitlock
2
  1. Você realmente não descreve o mecanismo de configuração, que IMHO é um pouco complicado. Como você faz com que todo o código em execução em um thread use a conexão de banco de dados A e todo o código na outra conexão de thread B? Como você bloqueia a injeção de um determinado recurso, porque o usuário atualmente conectado não tem permissão para acessá-lo?
  2. Não use um injetor global. Não use nada global, ou você também pode usar variáveis ​​globais. Não, o uso de fala OOP, como singleton ou "estático", em vez de global, não muda sua natureza global.
  3. Considere um contêiner com escopo dinâmico. Embora o escopo lexical tenha vencido legitimamente o escopo dinâmico, acredito que o escopo dinâmico seria um excelente substituto para o escopo global. A herança diferencial seria uma boa implementação (como na herança baseada em protótipo).
  4. Acredito que um mecanismo DI exigido pela linguagem deva ser realmente simples, nada daquelas coisas corporativas que são a norma em C # e Java. Um mecanismo de escopo dinâmico com uma camada de configuração simples na parte superior pode fazer o truque. As soluções corporativas podem ser colocadas em camadas por terceiros.
Waquo
fonte