【问题标题】:A class is recursive - when this class gets implemented, the parent class becomes recursive [duplicate]一个类是递归的——当这个类被实现时,父类变成递归的[重复]
【发布时间】:2019-06-16 19:50:10
【问题描述】:

举个例子:

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,但我无法理解它(特别是因为我刚刚开始学习它)。

有什么想法吗?

编辑:我不明白它是如何被标记为重复的。虽然我最终编写了自己的通用树,但我的问题中并没有要求它,也绝对没有要求图书馆。我正在寻求有关如何解决问题的一般建议,而我解决的解决方案最终偶然成为了通用树。 我提供了我的解决方案之后这个问题被关闭的事实让我相信有人阅读了答案,在 SO 上搜索了树,然后选择了第一个结果,这对任何人都没有帮助。 “原始”问题甚至没有为我的问题提供解决方案。这只不过是懒惰加上滥用管理员权限。

【问题讨论】:

  • Bar"implement" Foo 在这里如何?
  • C# 中没有“当存在具有特定属性的子类时静态更改父类”这样的东西。
  • 我真的不明白你的目的是什么
  • C# 不支持这种变化——Children 的类型在继承时不能改变。如果不需要继承,可以使用interface IFoo&lt;T&gt; where T : IFoo&lt;T&gt; { IEnumerable&lt;T&gt; Children { get; } },然后让FooBar 分别实现IFoo&lt;Foo&gt;IFoo&lt;Bar&gt;。如果您使用显式实现,您可以实际上将其与继承结合起来,但这会有点混乱。
  • 可能无法做到这一点。类似问题:stackoverflow.com/q/8727523

标签: c# design-patterns


【解决方案1】:

我想通了:

不要让任何类递归。相反,创建一个泛型类Recursive&lt;T&gt;

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&lt;Foo&gt; 转换为Recursive&lt;Bar&gt; 的方法,这很容易实现(我使用了扩展方法,因为这个想法借鉴了IEnumerable 和一般的函数式编程;它看起来更合适) :

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&lt;Foo&gt; 而不仅仅是Foo,问题就应该得到解决。这部分可能是特定于实现的。我将Foo 的构造函数设为私有,而是提供了一个RawFoo 类,以及从IEnumerable&lt;RawFoo&gt;Recursive&lt;Foo&gt;/IEnumerable&lt;Recursive&lt;Foo&gt;&gt; 的一些构造方法。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-10-26
    • 1970-01-01
    • 2012-04-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多