复杂的继承与泛型

时间:2015-09-28 12:51:57

标签: c# generics inheritance

我们说我有一组类/接口:

class ObjectData { }
class UnitData : ObjectData { }
class Component1Data : UnitData { }
class Component2Data : UnitData { }

interface IObject { }
interface IUnit : IObject { }
interface IComponent1 : IUnit { }
interface IComponent2 : IUnit { }

abstract class Object<D, O, I>
    where D : ObjectData
    where O : Object<D, O, I>, I, new()
    where I : IObject
{ }

这里主要关注的是Object类,它是某个层次结构中的基类泛型类。类型参数&#34; O&#34;是一种指定从Object派生的实际类的类型的方法。因此,这样的事情可以在没有问题的情况下声明和编译:

class Unit : Object<UnitData, Unit, IUnit>, IUnit { }

但我想做的是定义另一个通用&#34;第二级&#34;从Object派生的类,它也应该作为几个类似的&#34;第三级&#34;的基类。实体。它必须是非抽象的,因为它也是某种实体。所以我需要定义这样的东西:

class Unit<D, I> : Object<D, Unit<D, I>, I>, IUnit
    where D : UnitData
    where I : IUnit
{ }

class Component1 : Unit<Component1Data, IComponent1>, IComponent1 { }
class Component2 : Unit<Component2Data, IComponent2>, IComponent2 { }

它会产生以下编译错误:

error CS0311: The type 'Unit<D, I>' cannot be used as type parameter 'O' in the generic type or method 'Object<D, O, I>'. There is no implicit reference conversion from 'Unit<D, I>' to 'I'.

问题是为什么?在我的愿景中Unit<D, I>正在实施IUnit,以及param&#34;我&#34;被指定为where I : IUnit,那么一切都应该没问题。这就是我的看法。我不明白的是什么?

2 个答案:

答案 0 :(得分:1)

就像其他人评论的那样,你的仿制品太复杂了。 至少,在我看来,不需要I类型参数,因为您的Object将实现相应的接口。

因此,代码可以简化为:

abstract class Object<D, O> : IObject
    where D : ObjectData
    where O : Object<D, O>
{
}

class Unit<D> : Object<D, Unit<D>>, IUnit
    where D : UnitData
{
}

如果没有完全理解O如何在Object层次结构中使用,很难说,是否可以丢弃O类型参数。

你提到过静态工厂方法 - 这绝对不是带来这种复杂性的理由。但是,当然,您对用例了解得更多。

答案 1 :(得分:1)

简化问题;

interface IObject { }
interface IUnit : IObject { }
interface IFoo : IUnit { }

abstract class Object<O, I>
    where O : Object<O, I>, I, new()
    where I : IObject
{}

class Unit : Object<Unit, IUnit>, IUnit
{
}

这很开心并且编译。我已将此I替换为IUnit。现在换成更多派生的东西:

class Unit : Object<Unit, IFoo>, IUnit

你得到错误:

  

类型&#39;单位&#39;不能用作类型参数&#39; O&#39;在通用   类型或方法&#39;对象&#39;。没有隐含的参考   转换为&#39; Unit&#39;到&#39; IFoo&#39;。

所以... Unit来自IUnit无法转换为IFoo,即使两者都实现IUnit ...因为Unit没有&# 39; t派生自IFoo ...这是对象的条件:

where O : Object<O, I>, I`

要求你做一些你不允许做的事情:

class Unit<I> : Object<Unit<I>, I>, I