您的通用类型是否可以继承?

时间:2019-10-01 17:15:32

标签: c# generics

我试图在保留通用类型的同时抽象一些功能。检查下面的代码

public interface IDataItem{}
public class DataItemImpl : IDataItem{}

这就是我的界面和实现。然后是服务接口,抽象和具体实现

public interface IDataMapper<T> where T : IDataItem{}
public abstract class AbstractDataMapper<T> : IDataMapper<T> where T : IDataItem
public class CustomDataMapper : AbstractDataMapper<DataItemImpl>, IDataMapper<DataItemImpl>

正如您所看到的,我的具体实现将通用类型声明为DataItemImpl,在实现IDataItem时我认为是正确的,因此满足了T的约束条件

我遇到的问题是,当我尝试将具体实现分配给这样的通用接口时:

IDataMapper<IDataItem> mapper = new CustomDataMapper();

我遇到一个大错误:

  

无法将类型'CustomDataMapper'隐式转换为'IDataMapper<IDataItem>'。存在显式转换(您是否缺少演员表?)

如果我明确地将其强制转换,编译器将停止抱怨,但这闻起来不好吗?在这一点上是否有可能实现?或者我的野心超出了我的能力范围?

2 个答案:

答案 0 :(得分:4)

仅由于两个类具有继承关系,所以不会使使用前一个类作为其通用参数的任何通用类或接口具有相同的关系。换句话说:

class Derived : Base { }

并不表示IMyInterface<Derived>IMyInterface<Base>之间的关系。为什么?好吧,想象一下一个List<Animal>经常被引用的例子。当然,LionGiraffe都是基类Animal的实现。如果现在我们可以简单地将List<Giraffe>强制转换为List<Animal>,则可以将Lion放入列表:

List<Animal> baseList = new List<Giraffe> { ... };
baseList.Add(new Lion()); // rrroaaaaaaaaaa

另一方面,接口可以通过将out关键字添加到通用参数来启用协方差。

因此,在您的情况下,您需要IDataMapper-接口是协变的:

public interface IDataMapper<out T> where T : IDataItem{}

这意味着of MSDN如下:

  

使用更多派生类型参数实例化的对象是   分配给使用较少派生类型参数实例化的对象。   分配兼容性得以保留。

答案 1 :(得分:3)

第一

public class CustomDataMapper : AbstractDataMapper<DataItemImpl> //, IDataMapper<DataItemImpl>

足够了,因为AbstractDataMapper<DataItemImpl>带来了实施IDataMapper<DataItemImpl>的要求。

接下来,如果执行此操作,您会发现强制转换要求消失

IDataMapper<DataItemImpl> mapper = new CustomDataMapper();

不同之处在于{<1>} IS-A CustomDataMapper直接 IS-A AbstractDataMapper<DataItemImpl>

IDataMapper<DataItemImpl>是-(不一定是唯一的)IDataMapper<DataItemImpl>,因为除IDataMapper<IDataItem>之外的其他类可能会在以后出现,并且也实现DataItemImpl