2009-03-15 4 views
15

È possibile definire un tipo generico in C# che si riferisce a se stesso?Tipi generici ricorsivi

E.g. Voglio definire un dizionario <> che detiene il suo tipo di TValue (per una gerarchia).

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

No, questo non è possibile. Potresti essere più specifico a ciò che stai cercando di ottenere? –

+0

lol Earwicker, devi essere d'accordo, è strano;) ... Ho anche pensato che non lo fosse (direttamente) .. – eglasius

+0

Penso che le persone vengano confuse perché una classe non può ereditare da se stessa (ovviamente, o avrebbe dimensioni infinite come non appena ha avuto alcun campo), né un generico eredita da un parametro di tipo, ma i parametri del nome e del tipo della classe possono comparire negli argomenti di tipo di una base generica. –

risposta

41

Prova:

class StringToDictionary : Dictionary<string, StringToDictionary> { } 

Poi si può scrivere:

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

principio generale per la ricorsione: trovare un modo per dare un nome al modello ricorsivo, in modo che possa fare riferimento a stesso per nome.

+0

+1 molto bello, che in realtà compila/corre – eglasius

+0

grazie! bene che il dizionario non è sigillato :) – laktak

+4

lambda calcolo per la vittoria! – data

7

Un altro esempio potrebbe essere albero generico

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; } } 
} 

Ora usarlo

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 
} 

Notare che non è possibile creare un'istanza direttamente Tree<T>. Deve essere una classe base per la classe nodo nell'albero. Pensa allo class Node : Tree<Node> { }.