Метод расширения C # в List с определенным типом - PullRequest
0 голосов
/ 29 апреля 2018

У меня есть следующие 2 метода расширения

namespace Services.Resources.Extensions
{
    public static class DataMapExtensions
    {
        public static T ToDTO<T>(this BaseModel model)
        {
            return Mapper.Map<T>(model);
        }

        public static List<T> ToDTO<T>(this List<BaseModel> models)
        {
            return Mapper.Map<List<T>>(models);
        }

    }
}

Первый метод работает отлично.

//Note: FlightRoute inherits BaseModel
FlightRouteDTO foo = new FlightRoute().ToDTO<FlightRouteDTO>(); //This works!

Однако второй метод, похоже, не работает.

List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>(); //This doesn't work!

Компилятор говорит

Ошибка CS1929 «List » не содержит определения для «ToDTO», и наилучшая перегрузка метода расширения «DataMapExtensions.ToDTO (List )» требует приемник типа «List «

Но FlightRoute относится к типу BaseModel. Если я изменю тип bar на явно List<BaseModel> ..., то проблема исчезнет.

List<FlightRouteDTO> bar = new List<BaseModel>().ToDTO<FlightRouteDTO>(); //Why does it only work this way?

Я что-то упускаю из виду?

Ответы [ 3 ]

0 голосов
/ 29 апреля 2018

Лучший способ решить эту проблему - изменить подпись следующим образом:

public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
    return Mapper.Map<List<T>>(models);
}

На самом деле вам не нужно принимать List, потому что вы ничего не делаете со списком со значением, и AutoMapper понимает любой тип «коллекции», который вы передаете ему. IEnumerable<T> достаточно, и поскольку он ковариантен относительно T, теперь он отлично работает в вашем случае:

// works
List<FlightRouteDTO> bar = new List<FlightRoute>().ToDTO<FlightRouteDTO>();
0 голосов
/ 29 апреля 2018

Это ожидаемое поведение: вы пытаетесь использовать List<FlightRoute> как List<BaseModel>, но только потому, что FlitghtRoute наследует от BaseModel, не делает List<FlitghtRoute> наследованным от List<BaseModel>: они совершенно разные типы.

Вместо этого вы можете использовать Covariance , используя интерфейсы вместо конкретных типов.

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

public static List<T> ToDTO<T>(this IEnumerable<BaseModel> models)
{
    return Mapper.Map<List<T>>(models);
}

Это потому, что IEnumerable<T> - это интерфейс с параметром ковариантный . Взглянув на справочный источник , вы заметите, что этот интерфейс объявлен с out T как параметр универсального типа, который указывает, что T является ковариантным и может быть заменен любым унаследованным типом, когда мы используем IEnumerable<T>.

0 голосов
/ 29 апреля 2018

Вы можете ввести параметр второго типа с ограничением:

public static List<T> ToDTO<T, K>(this List<K> models) where K : BaseModel
{
    return Mapper.Map<List<T>>(models);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...