Question

Est-il possible de construire un objet avec son constructeur interne au sein d'une méthode générique?

public abstract class FooBase { }

public class Foo : FooBase {
   internal Foo() { }
}

public static class FooFactory {
    public static TFooResult CreateFoo<TFooResult>()
    where TFooResult : FooBase, new() {
        return new TFooResult();
    }
}

FooFactory réside dans le même ensemble que Foo. Les classes appellent la méthode d'usine comme ceci:

var foo = FooFactory.CreateFoo<Foo>();

Ils obtiens l'erreur de compilation:

  

« Foo » doit être un type non abstrait avec un constructeur parameterless public afin de l'utiliser comme paramètre « TFooType » dans le type générique ou méthode 'FooFactory.CreateFoo ()

Y at-il moyen de contourner cela?

J'ai essayé aussi:

Activator.CreateInstance<TFooResult>(); 

Cela soulève la même erreur lors de l'exécution.

Était-ce utile?

La solution

Vous pouvez supprimer la contrainte et le retour new():

//uses overload with non-public set to true
(TFooResult) Activator.CreateInstance(typeof(TFooResult), true); 

bien que le client puisse le faire aussi. Ceci, cependant, est sujette à des erreurs d'exécution.

Ceci est un problème difficile à résoudre de manière sûre car la langue ne permet pas un declaraton constructeur abstrait.

Autres conseils

  

L'argument de type doit avoir un    publique constructeur parameterless. Lorsqu'il est utilisé conjointement avec d'autres   les contraintes, la nouvelle () doit contrainte   spécifier dernier.

http://msdn.microsoft.com/en-us/library /d5x73970.aspx

edit: donc pas, si vous utilisez une nouvelle () contrainte, vous ne pouvez pas passer cette classe, si vous ne l'utilisez pas contrainte nouvelle (), vous pouvez essayer d'utiliser la réflexion pour créer une nouvelle instance

public static TFooResult CreateFoo<TFooResult>()
where TFooResult : FooBase//, new()
        {
            return (TFooResult)typeof(TFooResult).GetConstructor(System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, new Type[] {}, null).Invoke(new object[]{});
            //return new TFooResult();
        }

Il peut y avoir quelques contournements comme ci-dessous, mais je ne pense pas que vous voulez aller de cette façon!

  • Mettre l'instruction switch à l'intérieur de l'usine qui va créer l'instance basée le type de paramètre de type.

  • Chaque mise en œuvre concrète de FooBase enregistrera avec FooFactory passage la méthode usine pour créer soi-même. Ainsi, FooFactory utilisera le dictionnaire interne

  • L'extension de la ligne similaire, sauf en correspondance entre le paramètre de type et de mise en œuvre concrète serait code externe (fichier xml, configuration, etc.). conteneurs du CIO / DI peut aussi aider ici.

public class GenericFactory
{
    public static T Create<T>(object[] args)
    {
        var types = new Type[args.Length];
        for (var i = 0; i < args.Length; i++)
            types[i] = args[i].GetType();

        return (T)typeof(T).GetConstructor(types).Invoke(args);
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top