Autofac – utilizando parâmetros para resolver dependências

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Em nosso post anterior Autofac – Injetando dependências através de construtores, vimos como injetar as dependências que precisamos através do método construtor de uma classe. Hoje nós vamos ver, como nós definimos qual implementação de uma interface, nós vamos injetar em nossa classe. Nós também vamos continuar usando o mesmo projeto usado no post anterior para fazer a evolução necessária proposta nesse post.

Para começar, vamos criar uma nova classe chamada LinguagemGO, que também implemente a interface ILinguagemProgramacao. Ela deve ficar com o código abaixo:

namespace AutofacDemoWin
{
    public class LinguagemGO : ILinguagemProgramacao
    {
        public string Nome
        {
            get
            {
                return "GO";
            }
        }

        public double Versao
        {
            get
            {
                return 1.5;
            }
        }
    }
}

Após criar uma nova classe, devemos registrá-la no container  do Autofac, então no nosso evento Load, vamos acrescentar uma linha registrando essa nova classe, então, ele deve ficar assim:

private void FormAutofacDemoWin_Load(object sender, EventArgs e)
{
 var builder = new ContainerBuilder();
 builder.RegisterType<LinguagemCSharp>().As<ILinguagemProgramacao>().InstancePerDependency();
 builder.RegisterType<LinguagemGO>().As<ILinguagemProgramacao>().InstancePerDependency();
 builder.RegisterType<DesenvolvedorNinja>().As<IDesenvolvedor>().InstancePerDependency();
 _container = builder.Build();
}

Até aí, nada de diferente do que fizemos anteriormente, porém, se rodarmos agora nossa aplicação, ao clicarmos no botão “Obter Linguagem usando Autofac”, a mensagem exibida não é mais “C#”, e sim “GO”. Isso acontece porque no nosso evento Load, o registro da classe LinguagemGO ocorre após o registro da classe LinguagemCSharp. Se invertermos essas linhas, ao clicar no botão, a mensagem mudará para “C#”. Ou seja, estamos dependentes da ordem de registro, algo completamente inviável para uma aplicação. Então como resolvemos esse problema? Como fazer para garantir que independente de qualquer ordem, ou de quantas novas classes que implementem a interface ILinguagemProgramacao, vamos sempre conseguir utilizar a classe LinguagemCSharp na nossa classe DesenvolvedorNinja? Com o Autofac isso é simples de se resolver, e só vamos precisar alterar o código do evento Load, mudando a forma de registrar a classe DesenvolvedorNinja, e as classes LinguagemGO e LinguagemCSharp. Altere o evento Load para conter o código abaixo:

private void FormAutofacDemoWin_Load(object sender, EventArgs e)
{
	var builder = new ContainerBuilder();

	builder.RegisterType<LinguagemCSharp>().As<ILinguagemProgramacao>().AsSelf().InstancePerDependency();
	builder.RegisterType<LinguagemGO>().As<ILinguagemProgramacao>().AsSelf().InstancePerDependency();

	builder.RegisterType<DesenvolvedorNinja>().As<IDesenvolvedor>().WithParameter(new ResolvedParameter(
		(pi, ctx) => pi.ParameterType == typeof(ILinguagemProgramacao),
		(pi, ctx) => ctx.Resolve<LinguagemCSharp>())).InstancePerDependency();

	_container = builder.Build();
}

O que tem de diferente, primeiro, adicionamos o método “AsSelf” nas linhas de registro das classes LinguagemGO e LinguagemCSharp, e com isso estamos dizendo ao container que essas classes podem ser solicitadas diretamente, e não precisam ser solicitadas apenas através de sua interface.

A outra mudança está na linha abaixo:

builder.RegisterType<DesenvolvedorNinja>().As<IDesenvolvedor>().WithParameter(new ResolvedParameter(
	(pi, ctx) => pi.ParameterType == typeof(ILinguagemProgramacao),
	(pi, ctx) => ctx.Resolve<LinguagemCSharp>())).InstancePerDependency();

O que fizemos nessa linha foi dizer ao Autofac, para que ele use a classe LinguagemCSharp como parâmetro para a variável “linguagemProgramacao” que é do tipo ILinguagemProgramacao esperada no construtor da classe DesenvolvedorNinja. Fizemos isso usando o método WithParameter, que recebe um objeto do tipo ResolvedParameter, e para ele passamos o tipo do parâmetro, e pedimos ao container a instância que desejamos passar usando o método Resolve. O legal de especificarmos o tipo do parâmetro, é que se nossa classe DesenvolvedorNinja recebesse dois parâmetros no construtor, o Autofac saberia para qual parâmetro passar a instância de LinguagemCSharp, sem exigir que passemos todos os parâmetros esperados pelo construtor dessa forma.

Em breve novos posts sobre o Autofac, fique ligado em nosso blog.

O código-fonte completo está disponível no GitHub: https://github.com/rdakar/autofac-parametros-para-injecao

Facebooktwittergoogle_plusredditpinterestlinkedinmail

Deixe uma resposta

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *