2016-11-28 10 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、COL 15):タイプ「Program.DataReader」がジェネリック型またはメソッド「Program.BaseReportService」タイプパラメータ「踏む」として使用することができません。
'Program.Dataataer'から 'Program.DataataReader'への暗黙的な参照変換はありません。

コンパイルエラー(行46、列15):タイプ 'Program.DataRriter'は、ジェネリックタイプまたはメソッド 'Program.BaseReportService'のタイプパラメータ 'TWriter'として使用できません。
'Program.DataWriter'から 'Program.IDataWriter'への暗黙的な参照変換はありません。

+1

タイプ引数としてどこに 'DataReader'を提供するのか分かりません。 – HimBromBeere

+0

@HimBromBeere パブリッククラスReportService:BaseReportService Vlad

+1

問題は、共変/相反の差異のためです。これを修正する最も簡単な方法は、 'public class DataReader:IDataReader '(および 'DataWriter'の場合と同様の変更)のように' DataReader'を宣言することです。 – kha

答えて

3

問題は、IDataReader<IReadParamModel, IReadResultModel>IDataReader<ReaderParamModel, ReadResultModel>は互換性のないタイプです。それらを適合させるためには、共/反動が必要であるが、TResult Get(TParam param);TParamは反禁制であり、TResultは共変であろう。つまり、2つのインターフェイスを現在の使用方法と互換性を持たせる方法はありません。

実装プロパティへのアクセスが不要な場合や、具体的な型を追加の汎用パラメータとして使用する場合は、インタフェースを直接使用することができます。次のコードには、共/反変的なIDataReaderインターフェイスに基づいて、異なるデザインを示す3つのセクションが含まれています。

コードは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; 
    } 
}