如何定义一个接口,以确保它的孩子和父母是与定义的接口相同的类型

问题描述:

所以我有一个工作的解决方案,但我只是不确定我是否过于复杂。如何定义一个接口,以确保它的孩子和父母是与定义的接口相同的类型

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

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只能包含自己类型的孩子。因此,IEntityPrototypeChildren的类型为IList<IEntityPrototype>,而Parent的类型为IEntityPrototype

一个解决方案是实现为每个从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; } 
} 

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

+2

您可能需要阅读埃里克利珀的[奇妙而又奇妙(HTTPS://blogs.msdn.microso ft.com/ericlippert/2011/02/03/curiouser-and-curiouser/),它讨论了“奇怪的循环模板模式”,以及它为什么不能在C#中使用它。 –

+0

@Damien_The_Unbeliever哇,那*非常*快。非常感谢,我不知道我所实施的实际上是一种模式。非常有见地。我的确在问自己,我的实施在未来的好处是否会超过它的缺点。虽然我看不出这种模式的全部垮台,但我现在可以理解为什么。如果你写出更彻底的答案,我会很乐意接受它。 –

+0

有些事情你不能执行.... –

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

Eric LippertZp Bappi这两个人写了关于此更多的人谁感兴趣。

[I] n的练习使用这种模式确实务实解决是很难的C#,否则建模方法的问题时,有次。[...]原因之一,人们为什么要做到这一点,是执行类型层次结构中的特定约束。

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

我对Lippert的帖子也提到了对CRTP的怀疑。他建议

你实现这种奇怪的模式 在C#之前觉得很辛苦

  1. ,因为它实际上并没有强制约束,你认为它
  2. 这很简单,因为它烤人谁读码
的面条

如果我明白你的要求,那么这可能会有所帮助。

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; } 
} 
+0

这是不正确的。 'IEntityPrototype接口:IHierarchicalPrototype '可以将'IPrototype'的任何孩子添加到它的'Children'中。但我希望它的孩子完全是“IEntityPrototype”类型的。 –