3 回答

TA貢獻1856條經驗 獲得超5個贊
這在嚴格的類型安全方式中是不可能的,因為類型安全是在編譯時確保的,這需要靜態聲明類型。但是樹是在運行時動態構建的,具有不同的節點類型。
要走的路是擁有一個可以是通用的靜態節點數據類型。可以從給定的基本數據類型導出不同類型的數據。使用多態來處理它們。即使用具有不同實現的相同方法集。
public class TreeNode<T>
{
public T Data { get; set; }
private List<TreeNode<T>> _children = new List<TreeNode<T>>();
public IEnumerable<TreeNode<T>> Children => _children;
public TreeNode<T> AddChild(T data)
{
var node = new TreeNode<T> { Data = data };
_children.Add(node);
return node;
}
public void VisitPreOrder(Action<T, int> action, int level)
{
action(Data, level);
foreach (TreeNode<T> node in Children) {
node.VisitPreOrder(action, level + 1);
}
}
}
public class Tree<T>
{
public TreeNode<T> Root { get; } = new TreeNode<T>();
public void VisitPreOrder(Action<T, int> action)
{
Root.VisitPreOrder(action, 0);
}
}
現在您可以擁有與樹完全無關的數據類:
public class A
{
public int Index { get; set; }
public virtual void PrintLine()
{
Console.WriteLine($"A {Index}");
}
}
public class B : A
{
public override void PrintLine()
{
Console.WriteLine($"B {Index}");
}
}
public class C : B
{
public override void PrintLine()
{
Console.WriteLine($"C {Index}");
}
}
從您的示例創建樹結構
TreeNode<A> node;
var tree = new Tree<A>();
tree.Root.Data = new B { Index = 0 }; // NodeClassB
tree.Root.AddChild(new C { Index = 1 }); // __NodeClassC
node = tree.Root.AddChild(new A { Index = 2 }); // __NodeClassA
node.AddChild(new B { Index = 3 }); // ____NodeClassB
node.AddChild(new B { Index = 4 }); // ____NodeClassB
node.AddChild(new A { Index = 5 }); // ____NodeClassA
node = tree.Root.AddChild(new A { Index = 6 }); // __NodeClassA
node.AddChild(new C { Index = 7 }); // ____NodeClassC
tree.Root.AddChild(new B { Index = 8 }); // __NodeClassB
tree.Root.AddChild(new C { Index = 9 }); // __NodeClassC
因為每個數據類型(基類型或派生類型)都做適合其類型的事情,所以您不需要知道它的確切類型。這稱為多態。這將打印樹結構:
tree.VisitPreOrder((item, level) => {
Console.Write(new string('_', 4 * level));
item.PrintLine();
});
B 0
____C 1
____A 2 ____B
3 ____B
4
________A 5
____A 6
________C 7
____B 8
____C 9
請注意,T在聲明Tree<T>andTreeNode<T>類時,您不需要知道具體的數據類型,因為它T是通用的。你也可以聲明
var stringTree = new Tree<string>();
var intTree = new Tree<int>();

TA貢獻1842條經驗 獲得超13個贊
您可能正在尋找復合模式,這是一種對樹結構建模的常用方法,例如一個文件系統,其中您有一個葉子(文件)和容器(文件夾),而容器可以包含其他容器或葉子本身。
在您的情況下,至少到目前為止您描述的方式要簡單一些,因為這些節點之間沒有行為差異。所以對于你的結構,節點實際上可以是淺的,你只需要在你的基類中實現組合。這樣,您就沒有葉子,而只有(不同的)容器。
public abstract class BaseNode
{
public IList<BaseNode> Children
{ get; } = new List<BaseNode>();
}
public class NodeClassA : BaseNode { }
public class NodeClassB : BaseNode { }
public class NodeClassC : BaseNode { }
然后你就可以構建你的結構了。
- 3 回答
- 0 關注
- 228 瀏覽
添加回答
舉報