Créer une classe générique avec constructeur interne
-
01-10-2019 - |
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.
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);
}
}