从方法返回更多继承的泛型类?

时间:2019-11-09 07:41:32

标签: c# generics inheritance covariance

我有这样的界面:

public interface IImportModel
{
}

和实现此接口的类:

public class MaterialImportModel: IImportModel
{
    public string Name { get; set; }
}

我也有导入处理器的接口:

public interface IImportProcessor<TModel> where TModel: IImportModel
{
    void Process(TModel model);
}

该接口的实现之一:

public class MaterialImportProccessor : IImportProcessor<MaterialImportModel>
{
    public void Process(MaterialImportModel model)
    {
        // do some logic here
    }
}

现在,我想创建Factory来实例化此类处理器。我有界面:

public interface IImportProcessorFactory
{
    IImportProcessor<IImportModel> Get(Parameter parameter);
}

我正在尝试创建实现:

    public class ImportProcessorFactory : IImportProcessorFactory
    {
        public IImportProcessor<IImportModel> Get(Parameter parameter)
        {
             switch (Parameter) 
             {
                case "Materials":
                     IImportProcessor<IImportModel> processor = new MaterialImportProccessor();
                     return processor;

                case "Companies":
                    IImportProcessor<IImportModel> processor = new CompaniesImportProccessor();
                    return processor;
             }
        }
    }

但我有例外:

  

错误CS0266无法将类型'MaterialImportProccessor'隐式转换为IImportProcessor<IImportModel>。存在显式转换(您是否缺少演员表?)

是正确的。但是我无法使用out关键字进行IImportProcessor协方差,因为我使用TModel作为Process(TModel method)方法的输入参数。

有什么方法可以重构此代码以使其正常工作?

已编辑

我决定提供有关我打算如何使用该工厂的更多信息。

var deserializer = _deserializerFactory.Get(/*some parameters*/);
var importProcessor = _importProcessorFactory.Get(someEunmValue);

var data = deserializer.Deserialize(file);
importProcessor.Process(data);

因此,我无法使导入处理器出厂通用。

5 个答案:

答案 0 :(得分:0)

您应该更改为:

public interface IImportModel
{

}

public class MaterialImportModel: IImportModel
{
    public string Name { get; set; }
}

public class CompanieImportModel: IImportModel
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public interface IImportProcessor
{
     void Process(IImportModel model);
}

public class MaterialImportProccessor : IImportProcessor
{
    public void Process(IImportModel model)
    {
        var obj = (MaterialImportModel) model;

        // do some logic here
    }
}

public interface IImportProcessorFactory
{
    IImportProcessor Get();
}


public class ImportProcessorFactory 
{
    public IImportProcessor Get(Parameter parameter)
    {
         switch (Parameter) 
         {
            case "Materials":
                 IImportProcessor processor = new MaterialImportProccessor();
                 return processor;

            case "Companies":
                IImportProcessor processor = new CompaniesImportProccessor();
                return processor;
         }
    }
}

答案 1 :(得分:0)

更新

https://dotnetfiddle.net/HYtWiN

考虑为工厂使用dynamic关键字:

    public interface IImportProcessorFactory 
    {
        dynamic Get(Parameter parameter);
    }

    public class ImportProcessorFactory : IImportProcessorFactory
    {
        public dynamic Get(Parameter parameter)
        { 
            switch (parameter)
            {
                case Parameter.Materials:
                    return new MaterialImportProccessor() ; 

                case Parameter.Companies:
                    return new CompaniesImportProccessor();
                default:
                    return null;
            }
        }
    }

因此您可以类似于以下方式使用它:

        var factory = new ImportProcessorFactory();
        var material = factory.Get(Parameter.Materials);
        var company = factory.Get(Parameter.Companies);


        var model = new MaterialImportModel();
        model.MaterialName = " Metal ";
        material.Process(model);

        var cModel = new CompanyImportModel();
        cModel.CompanyName = "Build Metal Company";
        company.Process(cModel);

享受!

答案 2 :(得分:0)

更新2

这是我今天能做到的最好的。

public interface IImportProcessor
{
     void Process();
}

public class ImportModel1 { public string Name { get; set; }}

public class ImportProcessor1 : IImportProcessor
{
    private readonly ImportModel1 data;
    public ImportProcessor1(ImportModel1 data) { this.data = data;}
    public void Process() => Console.WriteLine($"My name is {data.Name}");
}

public class ImportModel2{ public int Age { get; set; }}

public class ImportProcessor2 : IImportProcessor
{
    private readonly ImportModel2 data;

    public ImportProcessor2(ImportModel2 data) { this.data = data;}
    public void Process() => Console.WriteLine($"My age is {data.Age}");
}

public enum EType {One = 1, Two = 2}


public class ImportProcessorFactory
{
    public IImportProcessor Get(EType type, string file) 
    {   
        switch (type)
        {
            case EType.One: return new ImportProcessor1(JsonConvert.DeserializeObject<ImportModel1>(file));
            case EType.Two: return new ImportProcessor2(JsonConvert.DeserializeObject<ImportModel2>(file));
        }

        throw new NotImplementedException("Unable to work with '{type}'");
    }
}


class Program
{

    public static void Main() 
    {
        var f = new ImportProcessorFactory();

        var data1 = (EType.One, "{ Name: 'Vlad' }");
        var p1 = f.Get(data1.Item1, data1.Item2 );
        Console.WriteLine(p1.GetType());
        p1.Process();

        var data2 = (EType.Two, "{ Age: '20' }");

        var p2 = f.Get(data2.Item1, data2.Item2 );
        Console.WriteLine(p2.GetType());
        p2.Process();


    }
}

输出

ImportProcessor1
My name is Vlad
ImportProcessor2
My age is 20

更新1

删除模型接口并使处理器取T

public interface IImportProcessor<T>
{
    void Process(T model);
}

使用此设置,所有东西都应该放在一起。

public interface IImportProcessor<T>
{
    void Process(T model);
}

public class MaterialImportModel
{
    public string Name { get; set; }
}

public class MaterialImportProccessor : IImportProcessor<MaterialImportModel>
{
    public void Process(MaterialImportModel model)
    {
        // do some logic here
    }
}

public interface IImportProcessorFactory<T>
{
    IImportProcessor<T> Get();
}

public class ImportProcessorFactory : IImportProcessorFactory<MaterialImportModel>
{
    public IImportProcessor<MaterialImportModel> Get() => new MaterialImportProccessor();
}

(原答案)

我认为使IImportProcessor为非通用将使您的模型更加简单,并消除了一整类问题。

public interface IImportProcessor
{
    void Process(IImportModel model);
}

物料处理器应实现采用接口而不是具体类的Process。否则a)不符合合同要求,并且b)放弃了接口的好处:)。

public class MaterialImportProcessor : IImportProcessor
{
    public void Process(IImportModel model)
    {
        // do some logic here
    }
}

答案 3 :(得分:0)

我决定添加其他抽象类:

public abstract class ImportProcessor<TModel> : IImportProcessor<MaterialImportModel> where TModel: class
{
    public void Process(IImportModel model)
    {
        Process(model as TModel);
    }

    public abstract void Process(TModel model);
}

并修改了MaterialImportProccessor

public class MaterialImportProccessor : ImportProcessor<MaterialImportModel>
{
    public override void Process(MaterialImportModel model)
    {

    }
}

答案 4 :(得分:-1)

您是否尝试过使用as运算符添加提到的用户DevFlamur这样的演员?