Créer une instance de type générique?
Si BaseFruit
a un constructeur qui accepte un int weight
, je peux instancier un morceau de fruit dans une méthode générique de ce genre?
public void AddFruit<T>()where T: BaseFruit{
BaseFruit fruit = new T(weight); /*new Apple(150);*/
fruit.Enlist(fruitManager);
}
Un exemple est ajouté derrière les commentaires. Il semble que je ne peut le faire que si je donne BaseFruit
un constructeur sans paramètre, puis remplissez tout à travers des variables membres. Dans mon vrai code (pas sur les fruits), c'est plutôt pratique.
-Mise à jour-
Il semble donc qu'il ne peut pas être résolu par des contraintes de toute façon-là. À partir des réponses il y a trois solutions:
- Modèle De Fabrique
- Réflexion
- Activateur
J'ai tendance à penser que la réflexion est la moins propre, mais je ne peux pas décider entre les deux autres.
- BTW: aujourd'hui, je serais probablement résoudre ce avec la bibliothèque du Cio de choix.
- La réflexion et l'Activateur sont en fait étroitement liés.
Vous devez vous connecter pour publier un commentaire.
En outre un exemple plus simple:
Notez que l'utilisation de la contrainte new() sur T est seulement pour faire le compilateur de vérifier pour un public constructeur sans paramètre au moment de la compilation, le code utilisé pour créer le type est la classe Activator.
Vous devez vous assurer vous-même quant à la spécificité du constructeur existant, et ce type de critère peut être une odeur de code (ou plutôt quelque chose que vous devez juste essayer d'éviter dans la version actuelle sur le c#).
new object[] { weight }
.CreateInstance
est déclarée avec params,public static object CreateInstance(Type type, params object[] args)
, de sorte que vous pouvez juste fairereturn (T) Activator.CreateInstance(typeof(T), weight);
. Si il y a plusieurs paramètres, de les transmettre en tant que distincts des arguments. Seulement si vous avez déjà un construit énumérable de paramètres devriez-vous la peine de le convertir enobject[]
et passer àCreateInstance
.Vous ne pouvez pas utiliser de paramétrer constructeur. Vous pouvez utiliser un constructeur sans paramètre si vous avez un "
where T : new()
" contrainte.C'est une douleur, mais telle est la vie 🙁
C'est l'une des choses que je voudrais aborder avec "interfaces statiques". Vous seriez alors en mesure de contraindre T pour inclure des méthodes statiques, les opérateurs et les constructeurs, puis de les appeler.
Oui; changez d'où:
Toutefois, cela ne fonctionne qu'avec sans paramètre constructeurs. Vous devez avoir un autre moyen de réglage de votre propriété (la définition de la propriété elle-même ou quelque chose de similaire).
Solution plus simple
Activator.CreateInstance<T>()
Comme Jon l'a souligné, c'est la vie pour contraindre les non-constructeur sans paramètre. Cependant, une autre solution est d'utiliser un modèle de fabrique. Ceci est facilement constrainable
Encore une autre option est d'utiliser une approche fonctionnelle. Passer dans une méthode de fabrique.
Vous pouvez le faire en utilisant la réflexion:
EDIT: Ajout de constructeur == null vérifier.
EDIT: Une variante plus rapide à l'aide d'un cache:
Récemment je suis tombé sur un problème très similaire. Je voulais juste partager notre solution avec vous tous. J'ai voulu, j'ai créé une instance d'un
Car<CarA>
à partir d'un objet json à l'aide de ce qui avait enum:Comme un complément à user1471935 suggestion:
Pour instancier une classe générique à l'aide d'un constructeur à un ou plusieurs paramètres, vous pouvez maintenant utiliser la classe Activator.
La liste des objets sont les paramètres que vous souhaitez fournir. Selon Microsoft:
Il y a aussi une version générique de la méthode CreateInstance (
CreateInstance<T>()
) mais que l'on ne vous permet pas de fournir les paramètres du constructeur.J'ai créé cette méthode:
- Je l'utiliser de cette façon:
Code:
Il est encore possible, avec la haute performance, en procédant comme suit:
et
Les classes puis dériver de cette interface et de les initialiser en conséquence.
Veuillez noter que, dans mon cas, ce code fait partie d'un entourage de classe, qui a déjà <T> en tant que paramètre générique.
R, dans mon cas, est aussi une lecture uniquement classe. OMI, le public de la disponibilité de l'Initialiser() fonctions n'a aucun effet négatif sur l'immutabilité. L'utilisateur de cette classe pourrait mettre un autre objet, mais ce ne serait pas modifier la collection sous-jacente.