возвращение конкретного обобщенного типа на основе ограничения

Вопрос или проблема

У меня есть метод, который вызывает ошибку компиляции, следующую:

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, позволяет создать более стабильный и поддерживаемый код, который легче модифицировать и расширять в будущем.

Оцените материал
Добавить комментарий

Капча загружается...