如何定义一个接口以确保其子项和父项与定义的接口具有相同的类型

How to define an interface that ensures it's children and parent are of the same type as the defined interface

所以我有一个可行的解决方案,但我不确定我是否使事情过于复杂。

假设我们有以下两个接口:

public interface IPrototype
{
    Guid Id { get; set; }
    string Name { get; set; }
}

public interface IHierarchicalPrototype : IPrototype
{
    IHierarchicalPrototype Parent { get; set; }
    IList<IHierarchicalPrototype> Children { get; set; }
}

现在假设存在许多 IHierarchicalPrototype 的实现,例如IEntityPrototypeIFieldPrototype.

在上面的定义中,Parent 可以是任何 IHierarchicalPrototypeIEntityPrototypeChildren 列表可以包含任何 IHierarchicalPrototype.

不过我想确定的是 IHierarchicalPrototype 只能包含其自身类型的子项。所以 IEntityPrototypeChildrenIList<IEntityPrototype> 类型,而 ParentIEntityPrototype.

类型

一个解决方案是为每个派生自 IHierarchicalPrototype 的原型实现 ChildrenParent,但必须有更简单的方法!

我想到的是泛型的解决方案。

而不是定义

interface IEntityPrototype : IHierarchicalPrototype {}

我可以用这样的泛型来定义它:

interface IEntityPrototype : IHierarchicalPrototype<IEntityPrototype>

虽然我无法摆脱多余的泛型类型参数。我希望泛型类型参数始终与我当前定义的接口相匹配,实际上只需要上面的 如果我想要像这样的混合原型(我不需要)

// this will never happen!
interface IEntityPrototype : IHierarchicalPrototype<IFieldPrototype>

这里还有IHierarchicalPrototype接口的通用定义

public interface IHierarchicalPrototype<THierarchical> : IPrototype
    where THierarchical : IHierarchicalPrototype<THierarchical>
{
    IHierarchicalPrototype<THierarchical> Parent { get; }
    IList<IHierarchicalPrototype<THierarchical>> Children { get; }
}

您可以想出任何替代或更优雅的解决方案吗?

如果我理解您的要求,那么这可能会有所帮助。

public interface IPrototype
{
    Guid Id { get; set; }
    string Name{ get; set; }
}

public interface IHierarchicalPrototype<T> : IPrototype where T:IPrototype
{
    T Parent{ get; }
    IList<T> Children { get; }
}

感谢@Damien_The_Unbeliever 我现在知道我实现的实际上是一个名为 couriously recurring template pattern (CRTP) 的模式。

Eric Lippert and Zp Bappi 都写了这篇文章是为了对更多感兴趣的人。

[I]n practice there are times when using this pattern really does pragmatically solve problems in ways that are hard to model otherwise in C#.[...] One reason why people want to do this is to enforce a particular constraint in a type hierarchy.

这个确切的原因是我试图用我的代码实现的。

Lippert 的 post 中也提到了我对 CRTP 的疑虑。他建议

to think very hard before you implement this sort of curious pattern in C#

  1. because it doesn't actually enforce the constraint you think it does
  2. this is simply because it bakes the noodle of anyone who reads the code