该类型不能用作泛型类型或方法 'BaseController<T>' 中的类型参数 'T'。没有隐式引用

The type cannot be used as type parameter 'T' in the generic type or method 'BaseController<T>'. There is no implicit reference

我正在尝试创建一个泛型来简化我的代码(这是一个网络 api 项目),但不知何故它最终变得比我预期的更复杂。我要实现的是这样的:

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

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>

我收到一条错误消息

The type 'Receipts' cannot be used as type parameter 'T' in the generic type or method 'BaseController'. There is no implicit reference conversion from 'Receipts' to 'IBackend'.

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

解决这个问题的最简单方法是:

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

然后这样使用

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

语法不是那么紧凑,但它很有魅力,没有协变或逆变的额外含义。

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

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

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

在 BaseController 上你有这个条件:

where T: IBackend<IDatabaseTable>

但收据继承了 IBackend,它与 IBackend 不直接兼容。您可以在 BaseController 上添加 2 个通用参数:

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

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

public class ReceiptsBaseController : BaseController<Receipts, ReceiptIndex>

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

将 IBackend 接口更改为如下所示:

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