在C#我有一个侵入树结构,如下所示:

public abstract class Node
{
    Container parent;
    Node nextNode;
    Node previousNode;

    public abstract class Container : Node
    {
        Node firstChild;
        Node lastChild;
    }
}

这可被添加到树中继承,这取决于它们是否能有儿童或者也不NodeContainer的各种对象。

通过使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; }
    }
}

编译就好了。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top