2016-11-28 176 views
2

如何修复?为什么我不能使用这种结构?C#多重泛型继承

using System; 

public class Program 
{ 

    public interface IReadParamModel{ } 
    public interface IReadResultModel{ } 
    public interface IWriteParamModel{ } 
    public interface IWriteResultModel{ } 

    public interface IDataReader<TParam, TResult> where TParam : IReadParamModel where TResult : IReadResultModel 
    { 
     TResult Get(TParam param); 
    } 

    public interface IDataWriter<TParam, TResult> where TParam : IWriteParamModel where TResult : IWriteResultModel 
    { 
     TResult Write(TParam param); 
    } 

    public abstract class BaseReportService<TReader, TWriter> 
     where TReader : IDataReader<IReadParamModel, IReadResultModel> 
     where TWriter : IDataWriter<IWriteParamModel, IWriteResultModel> 
    { 
      TWriter writer; 
      TReader reader; 
    } 

    public class ReaderParamModel : IReadParamModel { } 
    public class ReadResultModel : IReadResultModel { } 

    public class WriteParamModel : IWriteParamModel { } 
    public class WriteResultModel : IWriteResultModel { } 

    public class DataReader : IDataReader<ReaderParamModel, ReadResultModel> 
    { 
     public ReadResultModel Get(ReaderParamModel param) { return null; }  

    } 

    public class DataWriter : IDataWriter<WriteParamModel, IWriteResultModel> 
    { 
     public IWriteResultModel Write(WriteParamModel param){ return null; } 
    } 

    public class ReportService : BaseReportService<DataReader, DataWriter> 
    { 

    } 
} 

编译错误(线46,列15):类型“Program.DataReader”不能被用作在通用类型或方法“Program.BaseReportService”类型参数“行者”。
没有从'Program.DataReader'到'Program.IDataReader'的隐式引用转换。

编译错误(第46行,第15列):类型'Program.DataWriter'不能用作泛型类型或方法'Program.BaseReportService'中的类型参数'TWriter'。
没有从'Program.DataWriter'到'Program.IDataWriter'的隐式引用转换。

+1

我看不出你在哪里提供'DataReader'作为类型参数。 – HimBromBeere

+0

@HimBromBeere public class ReportService:BaseReportService Vlad

+1

问题在于co/contra方差的性质。修复它的最简单方法就是像这样声明DataReader:public class DataReader:IDataReader '(和'DataWriter'类似的变化)。 – kha

回答

3

的问题是,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; 
    } 
}