Si BaseFruit
un constructeur accepte un int weight
, puis-je instancier un fruit dans une méthode générique comme celle-ci?
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 puisse le faire que si je donne BaseFruit
un constructeur sans paramètre et que je remplis tout par le biais de variables membres. Dans mon vrai code (pas sur les fruits), c'est plutôt peu pratique.
-Update-
Il semble donc que cela ne puisse être résolu par aucune contrainte. D'après les réponses, il existe trois solutions possibles:
- Modèle d'usine
- Réflexion
- Activateur
J'ai tendance à penser que la réflexion est la moins nette, mais je ne peux pas choisir entre les deux autres.
Réponses:
De plus, un exemple plus simple:
Notez que l'utilisation de la contrainte new () sur T ne sert qu'à faire vérifier par le compilateur un constructeur public sans paramètre au moment de la compilation, le code réel utilisé pour créer le type est la classe Activator.
Vous devrez vous assurer du constructeur spécifique existant, et ce type d'exigence peut être une odeur de code (ou plutôt quelque chose que vous devriez simplement essayer d'éviter dans la version actuelle sur c #).
la source
new object[] { weight }
.CreateInstance
est déclaré avec des paramètres,public static object CreateInstance(Type type, params object[] args)
vous pouvez donc simplement le fairereturn (T) Activator.CreateInstance(typeof(T), weight);
. S'il existe plusieurs paramètres, transmettez-les en tant qu'arguments distincts. Ce n'est que si vous avez déjà un énuméré de paramètres construit que vous devez vous soucier de le convertirobject[]
et de le transmettre àCreateInstance
.Func
qui crée la nouvelle instance. Supposons que l'Apple
utilisation du constructeur soitnew Apple(wgt)
. Ajoutez ensuite à laApple
classe cette définition:static Func<float, Fruit> CreateOne { get; } = (wgt) => new Apple(wgt);
En usine, définissezpublic static Fruit CreateFruitGiven(float weight, Func<float, Fruit> createOne) { return createOne(weight); }
Usage:Factory.CreateFruit(57.3f, Apple.CreateOne);
- qui crée et renvoie unApple
, avecweight=57.3f
.Vous ne pouvez utiliser aucun constructeur paramétré. Vous pouvez utiliser un constructeur sans paramètre si vous avez une
where T : new()
contrainte " ".C'est une douleur, mais telle est la vie :(
C'est une des choses que j'aimerais aborder avec les "interfaces statiques" . Vous seriez alors en mesure de contraindre T à inclure des méthodes statiques, des opérateurs et des constructeurs, puis à les appeler.
la source
Oui; changez votre endroit:
Cependant, cela ne fonctionne qu'avec des constructeurs sans paramètres . Vous devrez avoir un autre moyen de définir votre propriété (définir la propriété elle-même ou quelque chose de similaire).
la source
La solution la plus simple
Activator.CreateInstance<T>()
la source
Comme Jon l'a souligné, c'est la vie pour contraindre un constructeur sans paramètre. Cependant, une solution différente consiste à utiliser un modèle d'usine. C'est facilement contraignable
Encore une autre option consiste à utiliser une approche fonctionnelle. Passez dans une méthode d'usine.
la source
Vous pouvez le faire en utilisant la réflexion:
EDIT: ajout du constructeur == vérification nulle.
EDIT: Une variante plus rapide utilisant un cache:
la source
En complément de la suggestion de user1471935:
Pour instancier une classe générique à l'aide d'un constructeur avec un ou plusieurs paramètres, vous pouvez désormais utiliser la classe Activator.
La liste des objets sont les paramètres que vous souhaitez fournir. Selon Microsoft :
Il existe également une version générique de CreateInstance (
CreateInstance<T>()
) mais celle-ci ne vous permet pas non plus de fournir des paramètres de constructeur.la source
J'ai créé cette méthode:
J'utilise cela de cette façon:
Code:
la source
Récemment, je suis tombé sur un problème très similaire. Je voulais juste partager notre solution avec vous tous. Je voulais j'ai créé une instance d'un à
Car<CarA>
partir d'un objet json en utilisant qui avait une énumération:la source
Il est toujours possible, avec des performances élevées, en procédant comme suit:
et
Les classes pertinentes doivent alors dériver de cette interface et s'initialiser en conséquence. Veuillez noter que dans mon cas, ce code fait partie d'une classe environnante, qui a déjà <T> comme paramètre générique. R, dans mon cas, est également une classe en lecture seule. OMI, la disponibilité publique des fonctions Initialize () n'a aucun effet négatif sur l'immuabilité. L'utilisateur de cette classe pourrait placer un autre objet, mais cela ne modifierait pas la collection sous-jacente.
la source