2010-08-07 3 views
4

J'ai la toto classe comme ceci:Création d'une pile <T> avec le type anonyme

class Foo 
{ 
    public int id{get;set;} 
    public IEnumerable<Foo> Childs; 
     //some other properties 
} 

Maintenant, je veux traiter une logique métier sur un Foo-objet et tous ses enfants comme ceci:

public void DoSomeWorkWith(Foo x) 
{ 
    var firstItem = new {level = 0, item = x}; 
    var s = new Stack<?>(?); //What type to use? 
    s.Push(firstItem); 
    while(s.Any()) 
    { 
    var current = s.Pop(); 
    DoSomeBusiness(current.item); 
    DoSomeMoreBusiness(current.item); 
    Log(current.level, current.item.id); 
    foreach(Foo child in current.item.Childs) 
     s.Push(new {level = current.level + 1, item = child}); 
    } 
} 

J'ai besoin de garder une trace du niveau (relatif)/profondeur des enfants. Comment créer un Stack<T> pour le type anonyme? Bien sûr, je pourrais créer une classe simple au lieu du type anonyme (ou une fonction récursive plus compliquée), mais comment résoudre ce problème sans une classe supplémentaire?

+0

Pouvez-vous s'il vous plaît formater votre code :) –

+0

déjà fait :) –

+0

'Childs' lit un peu étrange, étant donné que le pluriel anglais de « enfant » est :) « enfants » – AakashM

Répondre

0

Vous pouvez simplement le mettre dans une méthode comme ceci:

public Stack<T> CreateStackWithInitialItem<T>(T initialItem) 
{ 
    var s = new Stack<T>(); 
    s.Push(initialItem); 
    return s; 
} 

et ensuite l'utiliser comme ça:

public void DoSomeWorkWith(Foo x) 
{ 
    var s = CreateStackWithInitialItem(new {level = 0, item = x}); 
    while(s.Any()) 
    { 
     ... 
    } 
} 
6

Que diriez-vous:

public static Stack<T> CreateEmptyStack<T>(T template) { 
    return new Stack<T>(); 
} 
... 
var stack = CreateEmptyStack(firstItem); 

Il utilise l'inférence de type générique pour gérer la T.

0

Vous pouvez simplifier votre code en utilisant récursion au lieu de pousser les choses sur un pile temporaire et objets temporaires. Par exemple:

// (If you're not using C# 4, you can replace the default level with a function 
// overload or just remove the default value) 

void ProcessFooRecursive(Foo foo, int level = 0) 
{ 
    DoSomeBusiness(foo); 
    DoSomeMoreBusiness(foo); 
    Log(level, foo.id); 

    var newDepth = level + 1; 
    foreach (var child in foo.Childs) 
    { 
     ProcessFooRecursive(child, newDepth); 
    } 
} 
1

Qu'en est-en utilisant tuples (System.Tuple<>) au lieu de types anonymes?

public void DoSomeWorkWith(Foo x) 
{ 
    var firstItem = new Tuple<int, Foo>(0, x); 
    var s = new Stack<Tuple<int, Foo>>(); 
    s.Push(firstItem); 
    while (s.Any()) 
    { 
     var current = s.Pop(); 
     DoSomeBusiness(current.Item2); 
     DoSomeMoreBusiness(current.Item2); 
     Log(current.Item1, current.Item2.id); 
     foreach (Foo child in current.Item2.Childs) 
      s.Push(new Tuple<int, Foo>(current.Item1 + 1, child)); 
    } 
} 

Même si ce n'est pas le cas d'utilisation principale pour les objets dynamiques (à travers vous connaissez tous les types impliqués au moment de la conception), vous pouvez également utiliser System.Dynamic.ExpandoObject. Si vous le faites, assurez-vous de tester les différences de performances à cause de la surcharge.

public void DoSomeWorkWith(Foo x) 
{ 
    dynamic firstItem = new ExpandoObject(); 
    firstItem.level = 1; 
    firstItem.item = x; 

    var s = new Stack<dynamic>(); 
    s.Push(firstItem); 
    while (s.Any()) 
    { 
     var current = s.Pop(); 
     DoSomeBusiness(current.item); 
     DoSomeMoreBusiness(current.item); 
     Log(current.level, current.item.id); 
     foreach (Foo child in current.item.Childs) 
     { 
      dynamic next = new ExpandoObject(); 
      next.level = current.level + 1; 
      next.item = child; 
      s.Push(next); 
     } 
    } 
} 
Questions connexes