该类型不能用作泛型类型或方法“BaseController <t>”中的类型参数“T”。没有隐含的参考

时间:2015-05-12 09:02:15

标签: c# generics inheritance covariance contravariance

我正在尝试创建一个通用来简化我的代码(它是一个web api项目),但不知怎的,它最终变得比我预期的更复杂。我想要实现的是这样的:

My First Idea

为了简化我的整个实际代码,这就是我写的:

public interface IDatabaseTable { }

public class ReceiptIndex: IDatabaseTable { }

public interface IBackend<T> where T: IDatabaseTable { }

public class Receipts : IBackend<ReceiptIndex> { }

public class Generic<T> : SyncTwoWayXI, IBackend<T> where T:IDatabaseTable { }

public class BaseController<T> : ApiController where T: IBackend<IDatabaseTable>, new () { }

上面的所有行都在其自己的文件中单独创建。

当我尝试创建从BaseController继承的控制器

public class ReceiptsBaseController : BaseController<Receipts>

我收到错误说

  

“收据”类型不能用作类型参数“T”   泛型类型或方法'BaseController'。没有隐含的   参考从'收据'转换为'IBackend'。

我试图找到一个类似的问题并最终得到一个叫做协方差和逆变问题的东西。任何人都可以就我正在尝试做的事情提供反馈,或者我可以做些什么来简化它。

4 个答案:

答案 0 :(得分:4)

解决这个问题的最简单方法是在不使用具有一些重要意义的协方差和逆变性的情况下:

public class BaseController<TBackend, TDatabaseTable>
    : ApiController
    where TBackend : IBackend<TDatabaseTable>, new() 
    where TDatabaseTable: IDatabaseTable
{ }

以这种方式使用

public class ReceiptsBaseController : BaseController<Receipts, ReceiptIndex>
{
}

语法不是那么紧凑,但它的作用就像一个魅力,没有协方差或逆变的额外含义。

答案 1 :(得分:1)

您可以尝试在IBackend中指定T。 像这样:

public class BaseController<T, TBackEndSubType> : ApiController
    where T : IBackend<TBackEndSubType>, new()
    where TBackEndSubType : IDatabaseTable { }

public class ReceiptsBaseController : BaseController<Receipts, ReceiptIndex> { }

答案 2 :(得分:0)

在BaseController上你有这样的条件:

where T: IBackend<IDatabaseTable>

但是收据中断了IBackend&lt; ReceiptIndex&gt;,它与IBackend&lt; IDatabaseTable&gt;不直接兼容。您可以在BaseController上添加2个通用参数:

public class BaseController<TBackend, TDatabaseTable> : ApiController 
    where TDatabaseTable: IDatabaseTable 
    where TBackend: IBackend<TDatabaseTable>, new () { }

然后你可以这样声明你的控制器:

public class ReceiptsBaseController : BaseController<Receipts, ReceiptIndex>

答案 3 :(得分:0)

使用out修饰符:https://msdn.microsoft.com/en-us/library/dd469487.aspx

将IBackend界面更改为:

 public interface IBackend<out T> where T : IDatabaseTable { }