Fonction générique sur une liste de classe dérivée
Question
Je pense que ma question est plutôt idiote, ou d’une autre façon de la formuler: je suis trop perdu dans mon code pour voir une solution de contournement pour le moment. Restez trop longtemps sur un problème, et votre vision devient de plus en plus étroite & Gt; & Lt ;. De plus, je ne suis pas assez bon avec l'héritage, le polymorphisme et ainsi
Voici l’idée: j’ai plusieurs listes de classes dérivées et j’aimerais appeler des fonctions génériques sur ces listes (accès et modification des membres de la classe de base). Je pense qu'il y a quelque chose à voir avec l'héritage, mais je n'arrive pas à le faire fonctionner comme je le veux pour le moment.
Voici un exemple très simple de ce que je compte faire:
class Baseclass
{
public int ID;
public string Name;
}
class DerivedClass1 : Baseclass
{
}
private void FuncOnBase(List<Baseclass> _collection)
{
// ...
foreach (Baseclass obj in _collection)
{
++obj.ID;
}
// ...
}
private void FuncTest()
{
List<DerivedClass1> collection1 = new List<DerivedClass1>();
collection1.Add(new DerivedClass1() { ID = 1 });
collection1.Add(new DerivedClass1() { ID = 2 });
collection1.Add(new DerivedClass1() { ID = 3 });
FuncOnBase(collection1); // ==> forbidden, cannot convert the derived class list to the base class list
}
La solution
Je dois aimer la variance. Un List<DerivedClass1>
n’est pas un List<Baseclass>
- sinon, FuncOnBase
pourrait essayer d’ajouter un Baseclass
à la liste, sans que le compilateur le repère.
Une astuce consiste à utiliser une méthode générique:
private void FuncOnBase<T>(List<T> _collection) where T : Baseclass
{
// ...
foreach (T obj in _collection)
{
obj.ID++;
}
// ...
}
En ce qui concerne l'exemple que j'ai présenté ci-dessus - notez que nous pouvons ajouter un T
à la liste; utile en particulier si nous ajoutons la contrainte T : new()
, ou si nous transmettons (par exemple) un params T[]
.
Notez également que IEnumerable<T>
devient une covariante dans C # 4.0 / .NET 4.0. Par conséquent, si vous transmettez simplement un IEnumerable<Baseclass>
(plutôt qu'une liste), cela fonctionnera & "tel quel &"; :
private void FuncOnBase(IEnumerable<Baseclass> _collection)
{
///...
}
Autres conseils
Si vous ne faites qu'un foreach
, déclarez FuncOnBase(IEnumerable<Baseclass> collection)
, vous pouvez appeler à partir de FuncTest
comme suit:
FuncOnBase(collection1.Cast<Baseclass>());
Lorsque vous déclarez une méthode avec un paramètre List<T>
mais n'utilisez que ses IEnumerable<T>
fonctionnalités, vous ajoutez des contraintes d'API qui ne veulent rien dire dans votre code.