问题
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:
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