通用约束,包括通用本身

问题描述

我确实想知道为什么不允许这种构造

public interface IComplexDecorator<Item,Component> : IComponent<Item>
    where Component : IComplexComponent<Item,IComplexDecorator<Item,Component>>
{

}

public interface IComplexComponent<Item,Decorator> : IComponent<Item>
    where Decorator : IComplexDecorator<Item,IComplexComponent<Item,Decorator>>
{

}

public interface IComponent<Item>
{

}

装饰器错误消息

IComplexDecorator '不能用作类型参数 通用类型或方法“ IComplexComponent 。没有来自的隐式引用转换 'Component.IComplexDecorator '到 'Component.IComplexDecorator >>'。

组件错误消息

'Component.IComplexComponent '不能用作类型参数'Component' 泛型类型或方法'IComplexDecorator '。有 没有来自的隐式引用转换 'Component.IComplexComponent '至 'Component.IComplexComponent >>'

解决方法

您的示例太复杂而无法使用,但是我在想的是问题不在于循环引用本身,而在于循环引用导致了什么。因此,让我们考虑以下示例:

public interface IBaseManager<TComponent>
   where TComponent : IBaseComponent<TComponent>
{ }

public interface IBaseComponent<TManager>
    where TManager : IBaseManager<TManager>
{ }

如果添加具体的类来实现接口,则更容易理解:

public class Manager : IBaseManager<Component> { }

public class Component : IBaseComponent<Manager> { }

如果您查看IBaseManager<Component>中的TComponentIBaseManager的类型约束,您会发现TComponent应该隐式转换为{{1} },其中IBaseComponent<TComponent>是我们的课程TComponent。因此,事实证明应该将Component强制转换为Component,但是我们的IBaseComponent<Component>仅实现Component。因此无法进行投射。

您可以说IBaseComponent<Manager>可以实现接口Component,但也会导致相同的问题,因此,如果您想了解为什么它,我鼓励您尝试一下。不起作用。

就像我之前说的,如果您使用它,您将了解添加第二个接口的实现无济于事,因此可以通过添加第二个通用参数来解决问题。

IBaseComponent<Component>

现在,如果遵循相同的逻辑,我们将看到 public interface IBaseManager<TComponent,TManager> where TComponent : IBaseComponent<TComponent,TManager> where TManager : IBaseManager<TComponent,TManager> {} public interface IBaseComponent<TComponent,TManager> {} public class Manager : IBaseManager<Component,Manager> { } public class Component : IBaseComponent<Component,Manager> { } (在我们的示例中为TComponent)应隐式转换为Component(即IBaseComponent<TComponent,TManager>在我们的示例中),这就是我们所拥有的。我们的IBaseComponent<Component,Manager>实现了Component

您还可以查看以下question,其中Jon Skeet显示了如何解决问题(我实际上从问题中举了一些例子):

,

我能够使用第3个泛型解决此问题。但是由于第三个通用解决方案还包含循环谓词,所以我不确定为什么它真正起作用。

public interface IComplexDecorator<Item,Component,Decorator> : IComponent<Item>
    where Component : IComplexComponent<Item,Decorator,Component>
    where Decorator : IComplexDecorator<Item,Decorator>
{

}

public interface IComplexComponent<Item,Component> : IComponent<Item>
    where Decorator : IComplexDecorator<Item,Decorator>
    where Component : IComplexComponent<Item,Component>
{

}