2010-08-13 5 views
1

Je souhaite construire une liste de types anonymes construits en itérant à travers deux autres listes dans une boucle imbriquée.Construction de listes génériques de types anonymes et de boucles imbriquées

var myList = new List<???>(); 
foreach (object x in GetAllX()) 
{ 
    if (Process(x)) 
    { 
     foreach (object y in GetAllY(x)) 
     { 
      myList.Add(new { 
       X = x, 
       Y = y 
      }); 
     } 
    } 
} 

Je sais que je peux construire une liste des types anonymes à l'aide ToList(), (voir this question), mais je ne vois pas comment je peux l'utiliser dans le cas ci-dessus. Notez que je ne peux pas modifier les méthodes GetAllX et GetAllY.

+0

possible duplicate of [Une liste générique de la classe anonyme] (http://stackoverflow.com/questions/612689/a-generic-list-of-anonymous-class) – nawfal

Répondre

4

La réponse simple est "vous ne devriez pas".

Il y a un hacky astuce qui vous permet de le faire:

var myList = new[] { new { X = (object) null, Y = (object) null } }.ToList(); 
myList.Clear(); 
foreach (object x in GetAllX()) 
    // ... 

Mais il serait vraiment plus raisonnable d'utiliser la façon dont il a été conçu:

var myList = GetAllX().Where(x => Process(x)) 
    .SelectMany(x => GetAllY(x).Select(y => new { X = x, Y = y })) 
    .ToList(); 

Si vous ne pouvez pas vraiment utiliser ce style purement fonctionnel pour une raison quelconque, ou si vous trouvez que vous devez instancier une telle liste à plusieurs endroits, vous devriez probablement déclarer une classe normale au lieu d'utiliser un anonymou. type s. Rappelez-vous que les types anonymes sont compilés dans les classes, donc il n'y a aucun avantage de performance pour les types anonymes, et même l'avantage de lisibilité/maintenabilité est discutable si vous devez recourir à des astuces comme le hacky en haut de ce post.

Certaines personnes suggèrent d'utiliser List<dynamic>, mais je le déconseille. Cela gêne gravement la maintenabilité, car les noms et les types de propriétés ne sont plus vérifiés lors de la compilation (vous pourriez en faire une erreur et obtenir un bogue d'exécution); il ralentit les performances d'exécution car chaque accès passe par le répartiteur dynamique; et aussi, une fois que vous avez placé vos objets dans cette liste, vous êtes fondamentalement coincé avec eux étant dynamique, parce que vous ne pouvez pas les renvoyer au type anonyme.

0

Vous avez deux choix ici. Tout d'abord, vous pouvez créer une classe simple qui a X et Y propriétés et faites votre liste une liste des objets de cette classe, comme ceci:

class NewClass 
{ 
    public object X; 
    public object Y; 
} 

var myList = new List<NewClass>(); 
foreach (object x in GetAllX()) 
{ 
    if (Process(x)) 
    { 
     foreach (object y in GetAllY(x)) 
     { 
      myList.Add(new NewClass() { 
       X = x, 
       Y = y 
      }); 
     } 
    } 
} 

Ou, vous pouvez simplement utiliser dans C# 4.0:

var myList = new List<dynamic>(); 
+0

Vous obtenez une vérification de type plus forte avec la première option. –

0

Puisque vous mettez X et Y dans la même liste, ils doivent avoir une classe/interface de base commune. Pas de relations entre eux? Alors pourquoi les mettez-vous dans la même liste! Ce n'est pas une bonne idée.

IEnumerable<BaseClass> AllXY = 
      GetAllX().Cast<BaseClass>().Union(GetAllY().Cast<BaseClass>()); 
foreach(var base in AllXY) 
{ 
    //do something to base, usually with polymorphism 
} 
+0

Pourquoi?X = catégories, Y = choses dans cette catégorie, ou peut-être X = répertoires, Y = fichiers dans ce répertoire. Il y a des tas de raisons pour lesquelles vous pourriez vouloir faire ceci dans des situations où c'est une bonne idée de garder toujours X et Y séparés dans la liste résultante. – Justin

+0

X = direcotires, Y = fichiers, les mettre dans une liste n'a pas de sens. –

+0

Je pense que vous avez mal lu ce que je fais. – Justin

1

Ce code ne serait-il pas le moyen le plus simple d'atteindre le résultat souhaité?

var myList = (from x in GetAllX() 
       where Process(x) 
       from y in GetAllY(x) 
       select new 
       { 
        X = x, 
        Y = y, 
       }).ToList(); 

(Timwi -. Je sais que c'est le « linqified » version de votre solution, mais je pensais que je posterais comme je pense que dans ce style, il est facile à lire et à suivre)