采用以下示例:
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上搜索树,然后选择了第一个结果,这对任何人都没有帮助。 “原始”问题甚至无法解决我的问题。这只不过是懒惰和滥用管理员权限。
答案 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