如何在C#中使用泛型侵入树类?
-
27-09-2019 - |
题
在C#我有一个侵入树结构,如下所示:
public abstract class Node
{
Container parent;
Node nextNode;
Node previousNode;
public abstract class Container : Node
{
Node firstChild;
Node lastChild;
}
}
这可被添加到树中继承,这取决于它们是否能有儿童或者也不Node
或Container
的各种对象。
通过使Container
一个内部类它意味着它可以访问专用成员Node
用于管理儿童的容器的列表。
这是一个好主意。但现在我想使它通用,这样我可以重复使用,同时保持类型安全 - 基本上将所有的树功能,泛型类以上节点和另一个节点和容器之间。这里是什么,我试图做一个粗略的设计:
public abstract class GenericNode<Node, Container>
where Node : GenericNode<Node, Container>
where Container : GenericNode<Node, Container>.GenericContainer
{
Container parent;
Node nextNode;
Node previousNode;
public abstract class GenericContainer : Node
{
Node firstChild;
Node lastChild;
}
}
其中,当然,不工作,因为你不能从GenericContainer
Node
继承(编译器错误的 CS0689 )。即使我把内部类要求(比如,通过使用internal
只是被我自己的图书馆小心)我仍然无法弄清楚,不会遇到同样的问题(错误)的设计。
(我不认为我会,但只是拼出来:我不是想“修理”的编译错误,我也不是在寻找一个简单的树实现。这是一个容器设计问题。)
和所以现在我有点难倒。有没有人有关于如何设计这个东西更好的想法?
编辑:一定要看一看的这个答案,这是在设计的另一个尝试,试图使用扩展方法来避免的问题‘注射’一类到继承层次(可惜不充分的工作)
解决方案
随着您的扩展方法的方法,如果你在接口上定义的继承约束(节点和容器之间),而不是什么,以及与接口装饰容器类。
{
MyNode n = new MyNode();
var c = new MyNode.MyContainer();
c.AddChild(n);
MySubNode s = new MySubNode();
c.AddChild(s);
OtherNode o = new OtherNode();
o.AddChild(o);
//compiler doesn't allow this, as you'd expect:
//c.AddChild(o);
}
public interface IContainer<TContainerType, TNodeType>
where TNodeType : GenericNode<TContainerType, TNodeType>
where TContainerType : TNodeType, IContainer<TContainerType, TNodeType>
{
}
public static class ContainerExtensions
{
public static void AddChild<TContainerType, TNodeType>(this IContainer<TContainerType, TNodeType> self, TNodeType node)
where TNodeType : GenericNode<TContainerType, TNodeType>
where TContainerType : TNodeType, IContainer<TContainerType, TNodeType>
{
GenericNode<TContainerType, TNodeType>.AddChild(self as TContainerType, node);
}
}
public class GenericNode<TContainerType, TNodeType>
where TNodeType : GenericNode<TContainerType, TNodeType>
where TContainerType : GenericNode<TContainerType, TNodeType>
{
TContainerType parent;
TNodeType nextNode;
TNodeType previousNode;
// Only used by Container
TNodeType firstChild;
TNodeType secondChild;
internal static void AddChild(TContainerType container, TNodeType node)
{
container.firstChild = node;
node.parent = container;
}
}
public class MyNode : GenericNode<MyContainer, MyNode>
{
}
public class MyContainer : MyNode, IContainer<MyContainer, MyNode>
{
}
public class MySubNode : MyNode
{
}
public class OtherNode : GenericNode<OtherNode, OtherNode>, IContainer<OtherNode, OtherNode>
{
}
其他提示
我的解决方案如下:
public class Tree<T> : ITree<T> where T : INode{
public T RootNode { get; private set; }
public Tree(T rootNode){
RootNode = rootNode;
}
}
public interface ITree<T> where T : INode{
T RootNode { get; }
}
public interface INode{
INode Parent { get; }
List<INode> Children { get; }
}
internal class Node : INode{
public INode Parent { get; private set; }
public List<INode> Children { get; private set; }
public Node( INode parent, List<INode> children = new List<INode>()){
Parent = parent;
Children = children;
}
}
HTH。
注意:!附加验证等ParentNode = null作为子节点;节点属于哪个被添加它等不是本示例中实现相同的父。
(不这样做 - 掉落意外扩展太把它留在,以帮助防止其他人;))
这是否帮助?
public abstract class GenericNode<Node, Container>
where Node : GenericNode<Node, Container>
where Container : GenericNode<Node, Container>.GenericContainer<Node>
{
Container parent;
Node nextNode;
Node previousNode;
public abstract class GenericContainer<Branch> where Branch: GenericNode<Node, Container>
{
private Leaf firstChild;
private Leaf secondChild;
}
}
另外在编译3.5。 Branch
被限制为可由所述Node
声明一个GenericNode
。
一种选择是从树的实际结构隔离客户端完全,通过不暴露节点对象直接:
public interface ITagged<T>
{
T Tag { get; set; }
}
public sealed class Tree<T>
{
//All Tree operations are performed here (add nodes, remove nodes, possibly move nodes, etc.)
//Nodes are only exposed as 'ITagged<T>', such as:
public ITagged<T> Root { get; private set; }
public IEnumerable<ITagged<T>> GetChildren(ITagged<T> item)
{
//Cast to Container and enumerate...
}
//Several other tree operations...
private class Node : ITagged<T>
{
Container parent;
Node nextNode;
Node previousNode;
public T Tag { get; set; }
}
private class Container : Node
{
Node firstChild;
Node lastChild;
}
}
在树现在可以包含任何类型的数据对象,而不从一个特殊类型的具有下降或包括任何属性控制树结构。树状结构全部由Tree类内部处理和树类中提供所有的树操作。现在,客户端是完全从实现细节隔离。所有客户端永远看到的是其数据的对象。如果您仍然希望能够还提供导航从节点,您可以提供在节点接口的链接回树,然后提供使用该树的方法来实现导航扩展方法。
我想我有一个工作的解决方案,但它并不完全工作:
public abstract class GenericNode<Node, Container>
where Node : GenericNode<Node, Container>
where Container : Node
{
Container parent;
Node nextNode;
Node previousNode;
// Only used by Container
Node firstChild;
Node secondChild;
public static class ContainerHelpers
{
public static void AddChild(Container c, Node n)
{
c.firstChild = n; // not a real implementation ;)
n.parent = c;
}
}
}
// EDIT: This does not work correctly! (see example below)
public static class GenericNodeExtensionMethods
{
public static void AddChild<Node, Container>(this Container c, Node n)
where Node : GenericNode<Node, Container>
where Container : Node
{
GenericNode<Node, Container>.ContainerHelpers.AddChild(c, n);
}
}
//
// Example Usage
//
public class MyNode : GenericNode<MyNode, MyContainer>
{
}
public class MyContainer : MyNode
{
}
public class MySubNode : MyNode
{
}
public class OtherNode : GenericNode<OtherNode, OtherNode>
{
}
class Program
{
static void Main(string[] args)
{
MyNode n = new MyNode();
MyContainer c = new MyContainer();
c.AddChild(n);
MySubNode s = new MySubNode();
//
// This does not work because it tries to fill the generic in the
// extension method with <MySubNode, MyContainer>, which does not
// fulfil the constraint "where Container : Node".
//
//c.AddChild(s);
OtherNode o = new OtherNode();
o.AddChild(o);
}
}
虽然仅暴露于容器的方法的扩展方法的方法不能正常工作,结构是这样的GenericNode类具有良好性质的容器和节点可以是相同的类 - 给最终用户具有特定的选项在树中键入可以有孩子,或允许所有类型的有孩子。
(也由于某种原因,扩展方法不会在IntelliSense显示在VC#2008 SP1,尽管它在2010年一样。)
仍在寻找更好的解决方案...
只是解决您的泛型类型参数的名称,并记住泛型类型参数添加到继承GenericNode。
即
public abstract class GenericNode<TNode, TContainer>
where TNode : GenericNode<TNode, TContainer>
where TContainer : GenericNode<TNode, TContainer>.GenericContainer
{
public TContainer Parent { get; set; }
public TNode Next { get; set; }
public TNode Previous { get; set; }
public abstract class GenericContainer : GenericNode<TNode, TContainer>
{
public TNode FirstChild { get; set; }
public TNode LastChild { get; set; }
}
}
编译就好了。