Autofac: Resolvendo tipos de variantes com argumentos do tipo entrada e saída

9

Esta pergunta é um acompanhamento da minha pergunta anterior: Autofac: Escondendo várias implementações contravariantes por trás de um composto .

Estou tentando encontrar as fronteiras do que podemos fazer com o suporte de covariância e contravariância do Autofac. Percebi que o ContravariantRegistrationSource do Autofac suporta apenas interfaces genéricas com um único parâmetro genérico que é marcado com a palavra-chave in . Isso parece limitar a utilidade desse recurso, e estou me perguntando se o Autofac tem outras formas de estender o suporte de covariância e contravariância.

Devo admitir que não estou perguntando isso por causa de um design de aplicativo real do qual estou trabalhando. Estou deliberadamente tentando encontrar os limites da Autofac em prol da educação.

Então, considere a seguinte interface:

public interface IConverter<in TIn, out TOut>
{
    TOut Convert(TIn value);
}

E a seguinte implementação:

public class ObjectToStringConverter : IConverter<object, string>
{
    string IConverter<object, string>.Convert(object value)
    {
        return value.ToString();
    }
}

E o seguinte registro:

var builder = new ContainerBuilder();

builder.RegisterSource(new ContravariantRegistrationSource());

builder.RegisterType<ObjectToStringConverter>()
    .As<IConverter<object, string>>();

var container = builder.Build();

Com esse design e configuração, esperaria poder fazer isso:

// This call succeeds because IConverter<object, string> is
// explicitly registered.
container.Resolve<IConverter<object, string>>();

// This call fails, although IConverter<string, object> is
// assignable from IConverter<object, string>.
container.Resolve<IConverter<string, object>>();

Ou deixe-me colocar de forma mais abstrata, com as definições dadas:

public class A { }
public class B : A { }
public class C : B { }

public class AToCConverter : IConverter<A, C> { ... }

E o seguinte registro:

builder.RegisterType<AToCConverter>()
    .As<IConverter<C, A>>();

Espero que as seguintes chamadas sejam bem-sucedidas:

container.Resolve<IConverter<C, A>>();
container.Resolve<IConverter<B, B>>();
container.Resolve<IConverter<A, C>>();

Como podemos fazer isso com o Autofac?

    
por Steven 06.09.2011 в 19:31
fonte

2 respostas

4

Acho que essa é uma limitação que dificilmente venceremos no Autofac, mas é interessante explorar.

Nós podemos fazer uma 'resolução' contrariadora porque, dado um argumento de tipo genérico, podemos encontrar todos os tipos de base / interface aos quais esse argumento seria passível de atribuição. Ou seja, dado string , podemos procurar implementações para object , IComparable etc.

Indo na direção oposta - de um tipo de argumento para todas as suas subclasses - não é tão fácil. Com object , precisaríamos de uma forma de procurar todo o resto.

Pode ser possel usar conhecimento dos componentes de concreto registrados no recipiente, e. faça a varredura de todos os componentes procurando por possíveis implementações e trabalhe ao contrário, mas isso não é ótimo para o Autofac porque confiamos em um modelo 'pull' para criar componentes preguiçosos em muitos casos.

Espero que isso seja uma boa ideia, interessado em ver o que você pensa.

    
por Nicholas Blumhardt 08.09.2011 / 06:40
fonte
1

Você está correto em observar que ContravariantRegistrationSource reconhece apenas tipos com um parâmetro genérico. Observando a fonte (atualmente na linha aprox. 166) você verá essa limitação bem ali. Analisando como a fonte de registro é necessária para fornecer possíveis candidatos, posso entender que o levantamento da limitação exigirá mais complexidade na implementação.

Eu diria que isso não prova que você atingiu os limites do Autofac, apenas os limites dessa fonte de registro específica. Deixarei como um exercício para o leitor melhorar a implementação de ContravariantRegistrationSource e tenho certeza de que o projeto do Autofac está mais do que feliz em aceitá-lo de volta ao núcleo.

    
por Peter Lillevold 07.09.2011 / 09:14
fonte