Как правильно реализовать универсальный метод интерфейса? - PullRequest
3 голосов
/ 16 апреля 2019

Я пытаюсь реализовать универсальный метод интерфейса, но получаю сообщение об ошибке.Я вставляю код, чтобы лучше объяснить, что я хочу сделать.

Я пытаюсь добиться того, чтобы: на основе некоторых входных данных (SomeModelA, SomeModelB) я хочу получить тот же тип возврата (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
    }
}

Я хочу знать на уровне класса WorkerA / WorkerB, что я имею дело с конкретной моделью, и на основании этого я хочу вернуть экземпляр класса Template. Проблема в том, что встроки, которые вызывают Process:

ProcessModels(someModels);

Я получаю сообщение об ошибке:

Ошибка CS1503 Аргумент 1: невозможно преобразовать из 'System.Collections.Generic.List of SomeModelA' в'System.Collections.Generic.List of GenericInterfacePuzzle.SomeModelA'

Любая обратная связь оценила, что здесь происходит неправильно, и почему она не распознает классы модели при передаче в функции.

Крис

1 Ответ

3 голосов
/ 16 апреля 2019

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) Теперь вам нужно указать в дочерних классах, к какой модели относится рабочий тип:

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) и последнее, что вы тестируете в основном методе:

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]!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...