Вопрос или проблема
У меня есть метод, который вызывает ошибку компиляции, следующую:
interface INoun {}
class Person : INoun {}
class Place : INoun {}
class Thing : INoun {}
enum NounTypes { Person, Place, Thing }
//...
List<T> GetListOfNouns<T>(NounType type) where T : class, INoun {
switch (type){
case NounType.Person:
return new List<Person>();
case NounType.Place:
return new List<Place>();
case NounType.Thing:
return new List<Thing>();
default:
throw new Exception("NO!!!");
}
}
Компилятор жалуется, что не может преобразовать List<Person>
в List<INoun>
. Как мне решить эту проблему? Является ли единственным решением явное приведение типов?
Ответ или решение
Вопрос, который вы задали, касается использования обобщенных типов и их ограничений в C#. В вашем случае проблема заключается в том, что метод GetListOfNouns<T>
пытается вернуть список конкретного типа (List<Person>
, List<Place>
, List<Thing>
), в то время как ожидается, что он будет возвращать список типа T
, который ограничен типом INoun
. Давайте разберем это более подробно и найдем решение.
Проблема
Ваша реализация метода:
List<T> GetListOfNouns<T>(NounType type) where T : class, INoun {
switch (type) {
case NounType.Person:
return new List<Person>();
case NounType.Place:
return new List<Place>();
case NounType.Thing:
return new List<Thing>();
default:
throw new Exception("NO!!!");
}
}
Содержит ошибку компиляции, потому что:
- Метод ожидает возвращать
List<T>
. - Однако в блоке
switch
создаются списки конкретных типов (List<Person>
,List<Place>
,List<Thing>
), что не может быть неявно преобразовано вList<T>
.
Решение
Одним из решений этой проблемы является использование обобщенной коллекции и возвращение обобщенного типа. При этом вы не сможете вернуть списки конкретных типов напрямую. Ниже приведен подход, который использует базовый тип в создании списка.
Возможный подход с помощью динамического создания списка
Вы можете использовать рефлексию или базовое представление списка. Давайте рассмотрим следующий подход:
List<INoun> GetListOfNouns(NounType type) {
switch (type) {
case NounType.Person:
return new List<INoun> { new Person() };
case NounType.Place:
return new List<INoun> { new Place() };
case NounType.Thing:
return new List<INoun> { new Thing() };
default:
throw new Exception("NO!!!");
}
}
Поддержка типизации
Данный подход сохраняет типизацию и предоставляет вам список объектов, соответствующих типу INoun
, что упрощает масштабируемость кода. Однако следует помнить, что журналы будут содержать элементы типа INoun
, что не позволит работать с ними как с экземплярами своего конкретного типа.
Если вам действительно нужно возвращать типизированный список на основе типа, вы могли бы использовать приведение типов или обрабатывать каждую реализацию по отдельности в своем коде, но это может быть невыгодно с точки зрения кода и производительности.
Заключение
Использование обобщенных типов в C# может представлять трудности, особенно при необходимости возвращать конкретные реализации. Разделение логики и возвращение типов через полиморфизм позволяет избежать проблем с совместимостью типов и делает ваш код более гибким. При обращении к интерфейсам и обобщениям всегда учитывайте возможность работы с базовыми типами, чтобы избегать явных преобразований.
Это решение, основанное на инкапсуляции списка в тип INoun
, позволяет создать более стабильный и поддерживаемый код, который легче модифицировать и расширять в будущем.