How do I solve the “cannot implicitly convert [typ

2020-07-22 04:15发布

问题:

I have the following interfaces:

public interface IQueryHandler<in TQuery, out TResult> where TResult : class 
                                                where TQuery : IQuery<TResult>
{
    TResult Handle(TQuery query);
}

public interface IQuery<TResult> // Doesn't require anything special, just used to guarantee that IQueryHandlers get the right parameters.
{
}

It's intended to be used by IQueryHandlers which will take in an IQuery<TResult> which defines a query that returns an object of type TResult. The IQueryHandler's Handle method then returns a TResult.

I have the interface implemented on a DataQueryHandlers class:

public class DataQueryHandlers : IQueryHandler<GetDataById, SomeData>
{
    private IDataSource source;

    public DataQueryHandlers(IDataSource source)
    {
        this.source = source
    }

    public SomeData Handle(GetDataById query)
    {
        // Get the data here and return SomeData object
    }
}

where SomeData is a data entity, and GetDataById is an IQuery<SomeData>

However, when I try to instantiate a specific instance:

private IQueryHandler<IQuery<SomeData>, SomeData> dataQueryHandlers;
private IDataSource source;

source = new DataSource(); // some data provider

dataQueryHandlers = new DataQueryHandlers(datasource); // This line won't compile

I get a compiler error:

Cannot implicitly convert type DataQueryHandlers to IQueryHandler<IQuery<SomeData>, SomeData>. An explicit conversion exists (are you missing a cast?)

I'm sure this is a covariant/contravariant related problem, but I fail to see where the mismatch is. Is there a problem with my in/out generic modifiers? Is what I'm trying to do fundamentally incorrect in some way? Am I missing some obvious "hair on a fish" scenario here?

回答1:

You should change your derived class to generic one to be able to do it. Change it to this:

public class DataQueryHandlers<in TQuery, out TResult> : IQueryHandler<TQuery, TResult> where TResult : class where TQuery : IQuery<TResult>
{
    private IDataSource source;

    public DataQueryHandlers(IDataSource source)
    {
        this.source = source
    }

    public TResult Handle(TQuery query)
    {
        // Get the data here and return TResult object
    }
}

More about Generic Classes you can find MSDN



标签: c# generics