2009-03-15 8 views
15

Est-il possible de définir un type générique en C# qui fait référence à lui-même?Types génériques récursifs

E.g. Je veux définir un dictionnaire <> qui contient son type comme TValue (pour une hiérarchie).

Dictionary<string, Dictionary<string, Dictionary<string, [...]>>> 
+0

Non, ce n'est pas possible. Pourriez-vous être plus précis sur ce que vous essayez d'accomplir? –

+0

lol Earwicker, tu dois convenir que c'est bizarre;) ... Je pensais aussi que ce n'était pas (directement) .. – eglasius

+0

Je pense que les gens deviennent confus parce qu'une classe ne peut pas hériter de lui-même (évidemment, ou aurait une taille infinie dès qu'il aura des champs), ni un générique ne peut hériter d'un paramètre de type, mais les propres paramètres de nom et de type de la classe peuvent très bien apparaître dans les arguments de type d'une base générique. –

Répondre

41

Essayez:

class StringToDictionary : Dictionary<string, StringToDictionary> { } 

Vous pouvez alors écrire:

var stuff = new StringToDictionary 
     { 
      { "Fruit", new StringToDictionary 
       { 
        { "Apple", null }, 
        { "Banana", null }, 
        { "Lemon", new StringToDictionary { { "Sharp", null } } } 
       } 
      }, 
     }; 

Principe général pour récursion: trouver un moyen de donner un nom au motif récurrent, il peut se référer à lui-même par son nom.

+0

+1 très agréable, qui compile/fonctionne – eglasius

+0

merci! bon que le dictionnaire n'est pas scellé :) – laktak

+4

calcul lambda pour la victoire! – data

7

Un autre exemple serait arbre générique

public class Tree<T> where T : Tree<T> 
{ 
    public T Parent { get; private set; } 
    public List<T> Children { get; private set; } 
    public Tree(T parent) 
    { 
     this.Parent = parent; 
     this.Children = new List<T>(); 
     if(parent!=null) { parent.Children.Add(this); } 
    } 
    public bool IsRoot { get { return Parent == null; } } 
    public bool IsLeaf { get { return Children.Count==0; } } 
} 

Maintenant, pour l'utiliser

public class CoordSys : Tree<CoordSys> 
{ 
    CoordSys() : base(null) { } 
    CoordSys(CoordSys parent) : base(parent) { } 
    public double LocalPosition { get; set; } 
    public double GlobalPosition { get { return IsRoot?LocalPosition:Parent.GlobalPosition+LocalPosition; } } 
    public static CoordSys NewRootCoordinate() { return new CoordSys(); } 
    public CoordSys NewChildCoordinate(double localPos) 
    { 
     return new CoordSys(this) { LocalPosition = localPos }; 
    } 
} 

static void Main() 
{ 
    // Make a coordinate tree: 
    // 
    //     +--[C:50] 
    // [A:0]---[B:100]--+   
    //     +--[D:80] 
    // 

    var A=CoordSys.NewRootCoordinate(); 
    var B=A.NewChildCoordinate(100); 
    var C=B.NewChildCoordinate(50); 
    var D=B.NewChildCoordinate(80); 

    Debug.WriteLine(C.GlobalPosition); // 100+50 = 150 
    Debug.WriteLine(D.GlobalPosition); // 100+80 = 180 
} 

Notez que vous ne pouvez pas instancier directement Tree<T>. Ce doit être une classe de base à la classe de noeud dans l'arbre. Pensez class Node : Tree<Node> { }.

Questions connexes