如何正确实现通用接口方法?

时间:2019-04-16 11:33:39

标签: c# generics interface

我正在尝试实现通用接口方法,但始终出现错误。我正在粘贴代码以更好地解释我想做什么。

我想要实现的是:基于一些输入数据(SomeModelA,SomeModelB),我想要获得相同的返回类型(模板)。

namespace GenericInterfacePuzzle
{
    class Program
    {
        static void Main(string[] args)
        {
            var workerA = new WorkerA();
            var itemsBasedOnModelA = workerA.Get(new List<SomeModelA>());

            var workerB = new WorkerB();
            var itemsBasedOnModelB = workerB.Get(new List<SomeModelB>());
        }
    }

    public interface IWorker
    {
        Template Get<T>(List<T> someModels);
    }

    public class WorkerA : IWorker
    {
        public Template Get<SomeModelA>(List<SomeModelA> someModels)
        {
            ProcessModels(someModels);
            return new Template(); // let's say it's based on the result of ProcessModels
        }

        private void ProcessModels(List<SomeModelA> models)
        {
            var x = models.First();
        }
    }

    public class WorkerB : IWorker
    {
        public Template Get<SomeModelB>(List<SomeModelB> someModels)
        {
            ProcessModels(someModels);
            return new Template(); // let's say it's based on the result of ProcessModels
        }

        private void ProcessModels(List<SomeModelB> models)
        {
            var x = models.First();
        }
    }

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

    public class SomeModelB
    {
        public string Age { get; set; }
    }
    public class Template
    {
        // Irrevelant return type
    }
}

我想在WorkerA / WorkerB类的级别上知道我正在处理的具体模型,并基于此我想返回一个Template类实例 问题是在调用Process的行中:

ProcessModels(someModels);

我收到一条错误消息:

  

错误CS1503参数1:无法从SomeModelA的“ System.Collections.Generic.List”转换为GenericInterfacePuzzle.SomeModelA的“ System.Collections.Generic.List”

任何反馈都赞赏这里可能出了什么问题,以及为什么当传递给函数时它不能识别模型类。

克里斯

1 个答案:

答案 0 :(得分:3)

1)您需要在接口级别上定义通用参数。否则,编译器将不知道T参数:

public interface IWorker<T> where T: SomeModel
{
    Template Get(List<T> someModels);
}

2)您需要进行约束,因为您可能不希望将任何类型赋予接口。最好为模型创建一个基类,并让它们从中继承:

public abstract class SomeModel { ... }    

public class SomeModelA : SomeModel
{
    public string Name { get; set; }
}

public class SomeModelB : SomeModel
{
    public string Age { get; set; }
}

这样,您可以直接在实现该接口的类的声明中指定模型(请参见第3点)

3)现在,您需要在子类中指定哪个模型属于哪个workertype:

public class WorkerA : IWorker<SomeModelA>
{
    public Template Get(List<SomeModelA> someModels)
    {
        ProcessModels(someModels);
        return new Template(); // let's say it's based on the result of ProcessModels
    }

    private void ProcessModels(List<SomeModelA> models)
    {
        var x = models.First();
    }
}

public class WorkerB : IWorker<SomeModelB>
{
    public Template Get(List<SomeModelB> someModels)
    {
        ProcessModels(someModels);
        return new Template(); // let's say it's based on the result of ProcessModels
    }

    private void ProcessModels(List<SomeModelB> models)
    {
        var x = models.First();
    }
}

您还应该在Get方法中删除通用规范!

public Template Get<SomeModelA>(List<SomeModelA> someModels)
                      ^
                      |
                   remove this

在实现接口时已经指定了以下内容:

public class WorkerA : IWorker<SomeModelA>

4),最后一件事是您在main方法中进行测试:

var worker = new WorkerA();
var itemsBasedOnModelA = worker.Get(new List<SomeModelA>());

var workerB = new WorkerB();
var itemsBasedOnModelB = worker.Get(new List<SomeModelB>());
                           ^
                           |
                    this should be [workerB]!