简体   繁体   English

继承中的C#多个泛型

[英]C# multiple generic in inheritance

How it can be fixed? 如何解决? Why I can not to use this constructions? 为什么我不能使用这种结构?

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>
    {

    }
}

Compilation error (line 46, col 15): The type 'Program.DataReader' cannot be used as type parameter 'TReader' in the generic type or method 'Program.BaseReportService'. 编译错误(第46行,第15列):类型'Program.DataReader'不能用作通用类型或方法'Program.BaseReportService'中的类型参数'TReader'。
There is no implicit reference conversion from 'Program.DataReader' to 'Program.IDataReader'. 没有从“ Program.DataReader”到“ Program.IDataReader”的隐式引用转换。

Compilation error (line 46, col 15): The type 'Program.DataWriter' cannot be used as type parameter 'TWriter' in the generic type or method 'Program.BaseReportService'. 编译错误(第46行,第15列):类型'Program.DataWriter'不能用作通用类型或方法'Program.BaseReportService'中的类型参数'TWriter'。
There is no implicit reference conversion from 'Program.DataWriter' to 'Program.IDataWriter'. 从“ Program.DataWriter”到“ Program.IDataWriter”没有隐式引用转换。

The problem is, that IDataReader<IReadParamModel, IReadResultModel> and IDataReader<ReaderParamModel, ReadResultModel> are incompatible types. 问题是IDataReader<IReadParamModel, IReadResultModel>IDataReader<ReaderParamModel, ReadResultModel>是不兼容的类型。 In order to make them compatible, co-/contravariance would be needed, but with TResult Get(TParam param); 为了使它们兼容,需要使用TResult Get(TParam param); /逆TResult Get(TParam param); ,但是要使用TResult Get(TParam param); , TParam would be contravariant and TResult would be covariant. ,则TParam将是协变的,而TResult将是协变的。 This means, there is no way to make the two interfaces compatible with their current usage. 这意味着,无法使这两个接口与其当前用法兼容。

The choices are, to use the interfaces directly if access to the implementation properties is not required or to use the concrete types as additional generic parameters. 选择是:如果不需要访问实现属性,则直接使用接口;或者将具体类型用作其他通用参数。 The following code contains three sections that demonstrate the different designs, based on the co-/contravariant IDataReader interface. 以下代码包含三部分,它们基于IDataReader /互变IDataReader接口,展示了不同的设计。

The code is restricted to the Reader part, since the examples for reader and writer are quite similar. 该代码仅限于Reader部分,因为Reader和writer的示例非常相似。 The Test method is used to highlight some differences in the actually available types at different inheritance levels. 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;
    }
}

If you need the concrete types for input and output (like in the 3rd example), you should check, if you really need to specify the reader type for the ReportService. 如果需要输入和输出的具体类型(如第三个示例中所示),则应检查是否确实需要为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;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM