简体   繁体   中英

How to correctly implement generic interface method?

I'm trying to implement generic interface method but keep getting an error. I'm pasting the code to better explain what I want to do.

What I'm trying to achieve is: based on some input data (SomeModelA, SomeModelB) I want to get the same return type (Template).

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

I want to know at the level of WorkerA/WorkerB class that I'm dealing with a concrete model, and based on that I want to return a Template class instance The problem is that in the lines that call Process:

ProcessModels(someModels);

I get an error saying:

Error CS1503 Argument 1: cannot convert from 'System.Collections.Generic.List of SomeModelA' to 'System.Collections.Generic.List of GenericInterfacePuzzle.SomeModelA'

Any feedback appreciated what might be going wrong here, and why doesn't it recognize the model classes when passed to the functions.

Chris

1) You need to define the generic parameter on the level of your interface. Otherwise the T parameter is not known to the compiler:

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

2) you need to make a constraint since you probably don't want any type to be given to your interface. It would be preferable to make a baseclass for your models and let them inherit from it:

public abstract class SomeModel { ... }    

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

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

This way it will allow you to specify the model directly in the declaration of the class which will implement the interface (see point 3)

3) Now you need to specify in the child classes which model belongs to which 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();
    }
}

You also should remove the generic specification in your Get method!

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

this is already specified when you implement the interface:

public class WorkerA : IWorker<SomeModelA>

4) and the last thing is you test in the main method:

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]!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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