一个类是递归的-实现此类后,父类将递归

时间:2019-01-23 09:08:51

标签: c# design-patterns

采用以下示例:

class Foo {
    public int SomeProperty { get; }
    public IEnumerable<Foo> Children { get; }
    // ....
}

如果另一个类(例如Bar)实现了Foo,则Foo变为非递归的,而Bar变为递归的。

class Bar {
    public Foo { get; } // At this point Foo.Children doesn't make sense anymore
    public IEnumerable<Bar> Children { get; } // How can I enforce this part
    // ...
}

当前,我需要为每个类编写两个版本,一个带有Children,另一个没有。继承使此过程变得不那么繁琐,但是我不能静态地保证将正确实现需求。我还考虑过一种类型更高的Recursive类型的monad模式,但是我无法将其包围(特别是因为我刚开始学习它)。

有什么想法吗?

编辑:我不知道如何将其标记为重复项。虽然最后我最终编写了自己的通用树,但我的问题中并不需要它,也绝对不需要库。我一直在寻求有关如何解决该问题的一般建议,我最终解决的问题最终是偶然的。在我提供解决方案后,这个问题就解决了,这一事实使我相信有人读了答案,在SO上搜索树,然后选择了第一个结果,这对任何人都没有帮助。 “原始”问题甚至无法解决我的问题。这只不过是懒惰和滥用管理员权限。

1 个答案:

答案 0 :(得分:-1)

我知道了:

不要使任何类都是递归的。而是创建一个通用类Recursive<T>

public class Recursive<T>
{
    public T Head { get; }
    public IEnumerable<Recursive<T>> Children { get; }

    public Recursive(T head, IEnumerable<Recursive<T>> children)
    {
        Head = head;
        Children = children;
    }
    public Recursive(Recursive<T> source)
    {
        Head = source.Head;
        Children = source.Children;
    }
}

接下来,我们需要一种将Recursive<Foo>转换为Recursive<Bar>的方法,该方法非常容易实现(我使用了扩展方法,因为该思想通常借鉴了IEnumerable和函数式编程;似乎更合适):<​​/ p>

public static Recursive<U> Select<T, U>(this Recursive<T> source, Func<T, U> selector)
{
    var head = selector(source.Head);
    var children = source.Children.Select(x => Select(x, selector));
    return new Recursive<U>(head, children);
}

仅此而已。只要您可以将第一个构造强制为Recursive<Foo>而不是Foo,就应该解决此问题。这部分可能是特定于实现的。我将Foo的构造函数设为私有,而是提供了RawFoo类,以及从IEnumerable<RawFoo>Recursive<Foo> / IEnumerable<Recursive<Foo>>的一些构造方法。

如果另一个对象需要Foo,则只能轻松获得Recursive<Foo>。当然,有人可以打电话给myFoo.Head,但很显然他们可能没有得到他们想要的所有信息。相反,调用Select要容易得多,就像下面的示例一样,它为程序员提供了Recursive<Bar>而不是Bar的实现:

var myBar = myFoo.Select(x => {
    var someBarProperty = // ...
    return new Bar(x, someBarProperty);
}
// typeof(myBar): Recursive<Bar>
// typeof(myBar.foo): Foo