Était-ce utile?

La solution

Modifier S'il vous plaît noter que cette réponse a été donnée avant que la question a été complètement changé au cours d'une édition. À cause de cela, il se réfère maintenant aux choses qui étaient présents que dans la question de l'origine indiqué. Je vous demande pardon pour tous les « pointeurs ballants ». : -)


Réponse courte:

Avec le code que vous avez posté, je ne vois pas une alternative à la coulée à IFoo<T>. Si vous ne le faites pas, le compilateur donnera un avertissement (sur ma machine, au moins).

réponse plus élaborée:

Votre code ont effectivement être de cette façon? Plus précisément, avez-vous besoin le casting en question en premier lieu?

Je suppose que vous allez appeler votre méthode de fabrication plus ou moins comme ceci:

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

Vous devez fournir le paramètre de modèle (string dans ce cas) explicitement parce qu'il ne peut être dérivé de tout argument de méthode (dans ce cas, car il n'y a pas en réalité pas du tout). De toute évidence, la méthode usine renverra une IFoo<string>.

Maintenant, puisque vous devez spécifier explicitement le type à l'exécution, vous pouvez tout aussi bien écrire:

var stringFoo = StringFoo.Create();

et ont donc une méthode de fabrication à l'intérieur StringFoo, comme celui-ci, qui fait inconditionnellement l'évidence:

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

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

En appliquant ce modèle à d'autres implémentations IFoo<T> aussi, cela vous évitera le bloc de chaîne if ou switch à l'intérieur FooFactory.CreateFoo<T>, rendre votre code plus facile, et de se débarrasser de la nécessité de casting (dont vous êtes préoccupé par).

Ne vous méprenez pas, je suis conscient que les méthodes d'usine supportant plus d'un type d'objet sont utiles dans certains cas; mais il semble dans votre cas, il cause plus d'ennuis que cela vaut la peine.


P.S:. Vous trouverez peut-être un aspect de certains conteneurs IoC intéressants. Ils doivent généralement être configurés, ce qui englobe un processus dans lequel vous enregistrez des types de béton (à savoir les classes d'implémentation) pour les interfaces abstraites; par exemple (ici en utilisant Autofac ):

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

Ensuite, plus tard, vous pouvez demander une instance d'objet d'un type abstrait:

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

La méthode Resolve est la partie intéressante. Vous fournissez avec un type abstrait, et en utilisant les types enregistrés, il renvoie un objet concret de type StringFoo. Regardez en elle, si elle ne semble pas exagéré de vous! : -)

Autres conseils

Pouvez-vous décrire le problème que vous résolvez avec ce mécanisme? Il est très probablement une façon plus claire de l'aborder.

Modifier

Et oui, le sent code. Vous avez ouvert la chambre gauche pour tout type, sauf que vous contraignez alors revenir à un seul type, et de générer une exception à l'exécution. Pourquoi un paramètre de type dans ce cas?

Vous pouvez essayer quelque chose comme ça ...

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 mieux encore, présenter votre conteneur IoC préféré (Windsor, carte de structure, etc.) et d'enregistrer tous les types qui mettent en œuvre IFoo là-bas et puis les résoudre en cas de besoin en place de l'appel Activator.CreateInstance.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top