#c# #generics #interface
#c# #дженерики #интерфейс
Вопрос:
Я пытаюсь реализовать общий метод интерфейса, но продолжаю получать ошибку. Я вставляю код, чтобы лучше объяснить, что я хочу сделать.
Чего я пытаюсь добиться, так это: на основе некоторых входных данных (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, что я имею дело с конкретной моделью, и на основе этого я хочу вернуть экземпляр класса шаблона
Проблема в том, что в строках, вызывающих Process:
ProcessModels(someModels);
Я получаю сообщение об ошибке:
Ошибка CS1503 Аргумент 1: не удается преобразовать из ‘System.Коллекции.Универсальный.Список SomeModelA’ to’System.Коллекции.Универсальный.Список GenericInterfacePuzzle.SomeModelA’
Любая обратная связь приветствуется, что здесь может быть не так, и почему он не распознает классы модели при передаче функциям.
Крис
Комментарии:
1. в какой строке вы получаете ошибку, кстати?
2. Вы никогда не используете свой
workerB
btw3. Общий параметр типа должен быть в интерфейсе, а не в методе:
public interface IWorker<T>
Затем вы можете реализовать то, что хотите :public class WorkerA : IWorker<SomeModelA>
.4. У вас есть 2 класса с одинаковыми именами
SomeModelA
, поэтому вы получили исключение выше. Попробуйте так =>var itemsBasedOnModelA = worker.Get(new List<GenericInterfacePuzzle.SomeModelA>());
Ответ №1:
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) и последнее, что вы тестируете в основном методе:
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]!