的问题是,IDataReader<IReadParamModel, IReadResultModel>
和IDataReader<ReaderParamModel, ReadResultModel>
是不兼容的类型。为了使它们兼容,需要共同/逆转,但是TResult Get(TParam param);
,TParam
将是逆变的,并且TResult
将是协变的。这意味着,无法使两个接口与其当前使用情况兼容。
如果不需要访问实现属性,或者使用具体类型作为附加通用参数,则可以直接使用接口。以下代码包含三个部分,它们基于共同/逆变的界面展示了不同的设计。
该代码仅限于Reader
部分,因为读者和作者的示例非常相似。 Test
方法用于突出显示不同继承级别的实际可用类型的一些差异。
public interface IReadParamModel { }
public interface IReadResultModel { }
public class ReaderParamModel : IReadParamModel { }
public class ReadResultModel : IReadResultModel { }
public interface IDataReader<in TParam, out TResult>
where TParam : IReadParamModel
where TResult : IReadResultModel
{
TResult Get(TParam param);
}
// First variant - much interface usage
public class DataReader_1 : IDataReader<IReadParamModel, ReadResultModel>
{
public ReadResultModel Get(IReadParamModel param) { return null; }
}
public abstract class BaseReportService_1<TReader>
where TReader : IDataReader<IReadParamModel, IReadResultModel>
{
protected TReader reader;
// input is interface, reader.Get result is interface
protected virtual IReadResultModel Test(IReadParamModel param)
{
var result = reader.Get(param);
return result;
}
}
public class ReportService_1 : BaseReportService_1<DataReader_1>
{
// input is interface, reader.Get result is concrete class
protected override IReadResultModel Test(IReadParamModel param)
{
var result = reader.Get(param);
return result;
}
}
// Second variant - less interface usage, more generic parameters
public class DataReader_2 : IDataReader<ReaderParamModel, ReadResultModel>
{
public ReadResultModel Get(ReaderParamModel param) { return null; }
}
public abstract class BaseReportService_2<TReader, TReaderParam>
where TReader : IDataReader<TReaderParam, IReadResultModel>
where TReaderParam : IReadParamModel
{
protected TReader reader;
// input is concrete class, reader.Get result is interface
protected virtual IReadResultModel Test(TReaderParam param)
{
var result = reader.Get(param);
return result;
}
}
public class ReportService_2 : BaseReportService_2<DataReader_2, ReaderParamModel>
{
// input is concrete class, reader.Get result is concrete class
protected override IReadResultModel Test(ReaderParamModel param)
{
var result = reader.Get(param);
return result;
}
}
// Third variant - fully parameterized
public class DataReader_3 : IDataReader<ReaderParamModel, ReadResultModel>
{
public ReadResultModel Get(ReaderParamModel param) { return null; }
}
public abstract class BaseReportService_3<TReader, TReaderParam, TReadResult>
where TReader : IDataReader<TReaderParam, TReadResult>
where TReaderParam : IReadParamModel
where TReadResult : IReadResultModel
{
protected TReader reader;
// input is concrete class, reader.Get result is concrete class
protected virtual TReadResult Test(TReaderParam param)
{
var result = reader.Get(param);
return result;
}
}
public class ReportService_3 : BaseReportService_3<DataReader_3, ReaderParamModel, ReadResultModel>
{
// input is concrete class, reader.Get result is concrete class
protected override ReadResultModel Test(ReaderParamModel param)
{
var result = reader.Get(param);
return result;
}
}
如果您需要的具体类型的输入和输出(如在第三个例子),你应该检查,如果你真的需要指定ReportService的读者类型。
// Fourth variant - decoupled
// the reader is not really needed for this example...
public class DataReader_4 : IDataReader<ReaderParamModel, ReadResultModel>
{
public ReadResultModel Get(ReaderParamModel param) { return null; }
}
public abstract class BaseReportService_4<TReaderParam, TReadResult>
where TReaderParam : IReadParamModel
where TReadResult : IReadResultModel
{
// reader is interface, can be assigned from DataReader_4 or different implementations
protected IDataReader<TReaderParam, TReadResult> reader;
// input is concrete class, reader.Get result is concrete class
protected virtual TReadResult Test(TReaderParam param)
{
var result = reader.Get(param);
return result;
}
}
public class ReportService_4 : BaseReportService_4<ReaderParamModel, ReadResultModel>
{
// input is concrete class, reader.Get result is concrete class
protected override ReadResultModel Test(ReaderParamModel param)
{
var result = reader.Get(param);
return result;
}
}
我看不出你在哪里提供'DataReader'作为类型参数。 – HimBromBeere
@HimBromBeere public class ReportService:BaseReportService –
Vlad
问题在于co/contra方差的性质。修复它的最简单方法就是像这样声明DataReader:public class DataReader:IDataReader'(和'DataWriter'类似的变化)。 –
kha