2010-04-23 4 views
10

J'essaie de stocker une liste d'objets génériques dans une liste générique, mais j'ai du mal à la déclarer. Mon objet ressemble à:Une liste générique de génériques

public class Field<T> 
{ 
    public string Name { get; set; } 
    public string Description { get; set; } 
    public T Value { get; set; } 

    /* 
    ... 
    */ 
} 

Je voudrais créer une liste de ceux-ci. Mon problème est que chaque objet dans la liste peut avoir un type distinct, de sorte que la liste peuplée pourrait contenir quelque chose comme ceci:

{ Field<DateTime>, Field<int>, Field<double>, Field<DateTime> } 

Alors, comment dois-je déclarer cela?

List<Field<?>> 

(Je voudrais rester aussi typé que possible, donc je ne veux pas utiliser un ArrayList).

+0

C'est une idée intéressante de "rester aussi sûr que possible", cependant, ne vivez-vous pas le concept http://en.wikipedia.org/wiki/YAGNI? Pensez à comment allez-vous accéder à cette liste, en avez-vous vraiment besoin? –

Répondre

21

C'est la situation où il vous peut bénéficier d'avoir une classe de base abstraite (ou interface) contenant les bits non génériques:

public abstract class Field 
{ 
    public string Name { get; set; } 
    public string Description { get; set; } 
} 

public class Field<T> : Field 
{  
    public T Value { get; set; } 

    /* 
    ... 
    */ 
} 

Ensuite, vous pouvez avoir un List<Field>. Cela exprime toutes les informations que vous connaissez réellement sur la liste. Vous ne connaissez pas les types de valeurs des champs, car ils peuvent varier d'un champ à l'autre.

+0

@Jon - La première classe devrait-elle être une classe générique ou simplement une classe simple? – Giorgi

+1

@Giorgi, 'abstract class Champ ' ressemble à une faute de frappe. J'ai pris la liberté de le corriger. –

+0

Il doit encore lancer pour obtenir le type de valeur réel ... mais c'est à peu près la seule solution à laquelle je peux penser, sans un type de "tuple" réel. – tames

5

Peut-être implémenter une interface.

interface IField 
{ 
} 

class Field<T> : IField 
{ 
} 

...

List<IField> fields = new List<IField>() { new Field<int>(), new Field<double>() }; 
+0

Cela le laisse dans la même position car IField ne contiendra pas le type (T). différent de simplement utiliser 'object' car il devra encore lancer pour obtenir la valeur – tames

+0

@tames, il est dans une meilleure position car les éléments de sa liste doivent implémenter IField (ou hériter de Field, dans l'exemple de Jon). liste est encore plus fortement typée qu'une liste d'objets –

+0

@anthony ...Je suis d'accord, et j'ai utilisé des solutions d'interface et de classe de base. – tames

5

Vous ne pouvez pas déclarer une liste des types génériques sans connaître le type générique au moment de la compilation.

Vous pouvez déclarer une List<Field<int>> ou un List<Field<double>>, mais il n'y a pas d'autre type de base commune pour Field<int> et Field<double> que object. Donc, le seul List<T> qui pourrait contenir différents types de champs serait List<object>.

Si vous voulez un type plus spécifique pour la liste, vous devez faire en sorte que la classe Field<T> hérite d'une classe ou implémente une interface. Ensuite, vous pouvez l'utiliser pour le type générique dans la liste.

Questions connexes