Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Recursive generic types

Tags:

c#

generics

Is it possible to define a generic type in C# that references itself?

E.g. I want to define a Dictionary<> that holds its type as TValue (for a hierarchy).

Dictionary<string, Dictionary<string, Dictionary<string, [...]>>> 
like image 881
laktak Avatar asked Mar 15 '09 09:03

laktak


People also ask

What is recursive generics in Java?

We can use generics while defining our builders to tell Java that return type of methods is not the builder's class but rather the subclass of the builder, hence recursive generic definition.

Which types can be generic parameters?

Generics means parameterized types. The idea is to allow type (Integer, String, … etc., and user-defined types) to be a parameter to methods, classes, and interfaces. Using Generics, it is possible to create classes that work with different data types.

What is the generic class type called?

Generic Classes These classes are known as parameterized classes or parameterized types because they accept one or more parameters.


2 Answers

Try:

class StringToDictionary : Dictionary<string, StringToDictionary> { } 

Then you can write:

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

General principle for recursion: find some way to give a name to the recursive pattern, so it can refer to itself by name.

like image 146
Daniel Earwicker Avatar answered Sep 29 '22 06:09

Daniel Earwicker


Another example would be generic tree

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

Now to use it

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 } 

Note that you cannot directly instantiate Tree<TDerived>. It has to be a base class to the node class in the tree. Think class Node : Tree<Node> { }.

like image 32
John Alexiou Avatar answered Sep 29 '22 06:09

John Alexiou