Pregunta

¿Fue útil?

Solución

Editar Tenga en cuenta que esta respuesta se le dio antes de la pregunta fue cambiado por completo otra vez en una edición. Debido a eso, ahora se refiere a cosas que sólo estaban presentes en la pregunta como se dijo en un principio. Yo pido perdón por todos los "punteros colgando". : -)


Respuesta corta:

Con el código que has publicado, no veo una alternativa a la fundición a IFoo<T>. Si no lo hace, el compilador dará una advertencia (en mi máquina, por lo menos).

respuesta más elaborada:

¿Tiene su código en realidad tiene que ser así? Más específicamente, ¿necesita el elenco que se trate en primer lugar?

supongo que se va a llamar a su método de fábrica más o menos así:

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

Tiene que proporcionar el parámetro de plantilla (string en este caso) de manera explícita porque no puede ser derivada de cualquier argumento de un método (en este caso porque no hay realmente ninguna en absoluto). Obviamente, el método de fábrica devolverá un IFoo<string>.

Ahora, ya que se debe especificar explícitamente el tipo en tiempo de ejecución, sólo podría escribir así:

var stringFoo = StringFoo.Create();

y por lo tanto tiene un método de fábrica en el interior StringFoo, como éste, que hace incondicionalmente lo obvio:

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

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

Mediante la aplicación de este modelo a otras implementaciones IFoo<T> también, esto le ahorrará el bloque de cadena if o switch dentro FooFactory.CreateFoo<T>, hacer que su código sea más fácil, y deshacerse de la necesidad de yeso (que usted está preocupado).

No me malinterpreten, yo soy consciente de que el apoyo a métodos de fábrica más de un tipo de objeto son útil en algunos casos; pero parece que en su caso se provoca más problemas de lo que vale.


P.S:. Es posible encontrar un aspecto de algunos contenedores IoC interesante. Por lo general, necesitan ser configurados, y esto abarca un proceso en el que se registre tipos concretos (es decir, las clases de implementación) para interfaces abstractas; por ejemplo (aquí usando Autofac ):

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

Luego, más tarde, puede solicitar una instancia de objeto de un tipo abstracto:

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

El método Resolve es la parte interesante. Usted le proporcione un tipo abstracto, y el uso de los tipos registrados, devolverá un objeto concreto del tipo StringFoo. Mirada en él, si no lo hace sonar como una exageración para usted! : -)

Otros consejos

Puede describir el problema que se está resolviendo con este mecanismo? No es muy probable que una forma más clara de acercarse a ella.

Editar

Y sí, el código de los olores. Tiene abierta sala de la izquierda para cualquier tipo, excepto que la restringirá entonces de nuevo a un solo tipo, y generar una excepción en tiempo de ejecución. ¿Por qué tener un parámetro de tipo en ese caso?

Se podría intentar algo como esto ...

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;
    }
}

O mejor aún, introducir su contenedor favorita de la COI (Windsor, mapa de estructura, etc.) y registrar todos los tipos que implementan IFoo allí y luego resolverlos cuando sea necesario, en lugar de la llamada Activator.CreateInstance.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top