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

坚强是说给别人听的谎言 提交于 2021-01-27 07:51:03

问题


I'm trying to create a generic to simplify my codes (it's a web api project), but at somehow it's ended up becoming more complicated than I expected. What I'm trying to implement is something like this:

My First Idea

To simplify my whole real code, this is what I've written:

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 () { }

All of the line above created separately in its own file.

When I try to create controller that Inherit from BaseController

public class ReceiptsBaseController : BaseController<Receipts>

I get an error said

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'.

I try to find a similar problem and end up with something called Covariance and Contravariance problem. Can anyone give feedback for what I'm trying to do or maybe something that can I do to simplify it.


回答1:


You can try to specify the T in IBackend. Like this:

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

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



回答2:


The easiest way to solve this, without using covariance and contravariance, which has some important implications, is this:

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

And use it in this way

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

The syntax is not so compact, but it works like a charm, without the extra implications of covariance or contravariance.




回答3:


On the BaseController you have this condition:

where T: IBackend<IDatabaseTable>

but receipts inhertits IBackend<ReceiptIndex>, which is not directly compatible with IBackend<IDatabaseTable>. You could add 2 generic parameters on your BaseController:

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

then you can declare your controller like this:

public class ReceiptsBaseController : BaseController<Receipts, ReceiptIndex>



回答4:


using the out modifier: https://msdn.microsoft.com/en-us/library/dd469487.aspx

Change the IBackend interface to look like this:

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


来源:https://stackoverflow.com/questions/30186261/the-type-cannot-be-used-as-type-parameter-t-in-the-generic-type-or-method-bas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!