我如何制作一个可以容纳父级和子级两种differnet通用类型的树数据结构

时间:2019-02-21 15:48:28

标签: c# generics architecture

我很ham愧地承认我在这个问题上坐了很多小时。但是我只想按照下图中的结构来实现它。...

我想用其中的大洲/国家/州和城市来模拟世界。每个模型都有其父对象的引用和其子对象的引用列表,但世界上只有子对象(因为不能有父对象),而城市仅具有父对象引用,因为它没有深入。 (我想实现它,例如“世界”没有父字段,同样,“城市”也没有List<Children>字段。

我将要像下面这样在树数据结构中实现它(我省略了实现): Only interfaces shown for simplicity

为了让您了解接口的代码,我在此处包括了最少的内容:

public interface IRoot<TChild>
{
    List<TChild> Children { get; set; }
    void AddChild(TChild child);
}
public interface ILeaf<TParent>
{
    TParent Parent { get; set; }
}
public interface INode<TParent, TChild> : IRoot<TChild>, ILeaf<TParent> { }

以及一些实施代码

public class Root<TChild> : IRoot<TChild>
{
    public List<TChild> Children { get; set; }
    public void AddChild(TChild child) { //... }
}
public class Leaf<TParent> : ILeaf<TParent>
{
    public TParent Parent { get; set; }
}
public class Node<TParent, TChild> : INode<TParent, TChild>
{
    private IRoot<TChild> root;
    private ILeaf<TParent> leaf;

    //...
}

最后,我要构建的类的代码

public class World : Root<Continent> { }
public class Continent : Node<World, Country> { }
public class Country : Node<Continent, State> { }
public class State : Node<Country, City> { }
public class City : Leaf<City> { }

这是问题所在:

现在要在Root<TChild>.AddChild(TChild)中添加子对象,我需要访问<TChlid>.Parent,因此需要像这样将通用TChild约束为ILeaf<IRoot<TChild>>

public class Root<TChild> : IRoot<TChild> where TChild : ILeaf<Root<TChild>>
{
    public void AddChild(TChild child)
    {
        child.Parent = this;
    }
}

但是这样做,我得到了错误

  

CS0311 C#该类型不能用作通用类型或方法中的类型参数。没有从到的隐式引用转换。

在这一行

public class World : Root<Continent> { }

1 个答案:

答案 0 :(得分:0)

最后,我找到了解决方案。它包括使基类Root<TChild>Node<TParent, TChild>抽象。设置孩子的父母将被委托给一个抽象方法。在解决了通用类型参数的具体实现中,访问Parent属性是没有问题的。

我也略微更改了界面。将孩子暴露为List<TChild>是有问题的,因为它允许任何人通过直接添加到列表中来绕开AddChild的添加逻辑,而忘记设置孩子的父母。

我也将接口中的Parent属性设为只读,因为设置器仅在实现中使用。

public interface IRoot<TChild>
{
    IReadOnlyList<TChild> Children { get; }
    void AddChild(TChild child);
}

public interface ILeaf<TParent>
{
    TParent Parent { get; }
}

public interface INode<TParent, TChild> : IRoot<TChild>, ILeaf<TParent>
{
}

基类:

public abstract class Root<TChild> : IRoot<TChild>
{
    private List<TChild> _children = new List<TChild>();
    public IReadOnlyList<TChild> Children => _children;

    public void AddChild(TChild child)
    {
        _children.Add(child);
        SetChildsParent(child);
    }

    protected abstract void SetChildsParent(TChild child);
}

public class Leaf<TParent> : ILeaf<TParent>
{
    public TParent Parent { get; internal set; }
}

public abstract class Node<TParent, TChild> : Root<TChild>, INode<TParent, TChild>
{
    public TParent Parent { get; internal set; }
}

请注意,Node是从Root继承的,因此我们仅需补充ILeaf的实现。

具体的实现类:

public class World : Root<Continent>
{
    protected override void SetChildsParent(Continent child) => child.Parent = this;
}

public class Continent : Node<World, Country>
{
    protected override void SetChildsParent(Country child) => child.Parent = this;
}

public class Country : Node<Continent, State>
{
    protected override void SetChildsParent(State child) => child.Parent = this;
}

public class State : Node<Country, City>
{
    protected override void SetChildsParent(City child) => child.Parent = this;
}

public class City : Leaf<State> { }