Pergunta

Foi útil?

Solução

Editar: Observe que esta resposta foi dada antes que a pergunta fosse completamente alterada em uma edição. Por causa disso, agora se refere a coisas que estavam presentes apenas na questão, conforme declarado originalmente. Eu imploro seu perdão para todos os "ponteiros pendurados". :-)


Resposta curta:

Com o código que você postou, não vejo uma alternativa ao elenco para IFoo<T>. Caso contrário, o compilador dará um aviso (pelo menos na minha máquina).

Resposta mais elaborada:

Seu código realmente precisa ser assim? Mais especificamente, você precisa do elenco em questão?

Suponho que você chamará seu método de fábrica mais ou menos assim:

var stringFoo = FooFactory.CreateFoo<string>();

Você precisa fornecer o parâmetro de modelo (string neste caso) explicitamente porque não pode ser derivado de nenhum argumento do método (neste caso, porque na verdade não há nenhum). Obviamente, o método da fábrica retornará um IFoo<string>.

Agora, como você precisa especificar explicitamente o tipo em tempo de execução, você pode escrever:

var stringFoo = StringFoo.Create();

e, portanto, tem um método de fábrica dentro StringFoo, assim, que incondicionalmente faz o óbvio:

public class StringFoo : IFoo<string>
{
    ...

    public static StringFoo Create()  // or alternatively, return an IFoo<string>
    {
        return new StringFoo();
    }
}

Aplicando este padrão a outro IFoo<T> As implementações também, isso salvará o você if cadeia ou switch Bloqueie dentro FooFactory.CreateFoo<T>, Facilite seu código e se livre da necessidade de lançar (com o qual você está preocupado).

Não me interpretem mal, estou ciente de que os métodos de fábrica que suportam mais de um tipo de objeto são Útil em alguns casos; Mas parece que, no seu caso, causa mais problemas do que vale a pena.


PS: Você pode encontrar um aspecto de alguns contêineres do COI interessante. Eles geralmente precisam ser configurados, e isso abrange um processo em que você registra tipos de concreto (ou seja, classes de implementação) para interfaces abstratas; por exemplo (aqui usando Autofac):

var builder = new ContainerBuilder();
builder.RegisterType<StringFoo>().As<IFoo<string>>();

Mais tarde, você pode solicitar uma instância de objeto de um tipo abstrato:

using (var container = builder.Build())
{
    var stringFoo = container.Resolve<IFoo<string>>();
    ...
}

o Resolve O método é a parte interessante. Você fornece um tipo abstrato e, usando os tipos registrados, ele retornará um objeto concreto do tipo StringFoo. Olhe para ele, se não parecer exagerado para você! :-)

Outras dicas

Você pode descrever o problema que está resolvendo com esse mecanismo? Provavelmente há uma maneira mais clara de abordá -lo.

Editar

E sim, o código cheira. Você deixou a sala aberta para qualquer tipo, exceto que a restringe a um único tipo e gera uma exceção em tempo de execução. Por que ter um parâmetro de tipo nesse caso?

Você poderia tentar algo assim ...

public static class FooFactory
{
    private static readonly Dictionary<Type, Type> FooTypesLookup;

    static FooFactory()
    {
        FooTypesLookup = (from type in typeof(FooFactory).Assembly.GetExportedTypes()
                          let fooInterface =
                            type.GetInterfaces().FirstOrDefault(
                                x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IFoo<>))
                          where fooInterface != null
                          let firstTypeArgument = fooInterface.GetGenericArguments().First()
                          select new { Type = type, TypeArgument = firstTypeArgument })
            .ToDictionary(x => x.TypeArgument, x => x.Type);
    }

    public static IFoo<T> CreateFoo<T>()
    {
        var genericArgumentType = typeof(T);
        Type closedFooType;
        return FooTypesLookup.TryGetValue(genericArgumentType, out closedFooType)
                ? (IFoo<T>) Activator.CreateInstance(closedFooType)
                : null;
    }
}

Ou melhor ainda, apresente seu contêiner IOC favorito (Windsor, mapa de estrutura, etc.) e registre todos os tipos que implementam o IFOO lá e resolvam -os quando necessário no lugar do ativador.CreateInstance Call.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top