Создать метод расширения задачи для отображения - PullRequest
1 голос
/ 18 марта 2019

Что я хочу

Мы используем AutoMapper , и весь наш уровень обслуживания асинхронный .Вот как выглядит наше отображение в действии API:

var response = (await this.service.GetAll())
    .AsQueryable()
    .ProjectTo<DataViewModel>();
...

Я хочу добиться чего-то вроде:

var response = await this.service
    .GetAll()
    .Map<DataViewModel>();

Что я сделал

Лучшее, что ядо сих пор достигнуто:

var response = await this.service
    .GetAll()
    .Map<DataServiceModel, DataViewModel>();

Методы расширения, выглядящие так:

// Task extension
public static async Task<IEnumerable<TDestination>> MapCollection<TSource, TDestination>(
    this Task<IEnumerable<TSource>> collection)
        => (await collection)
            .MapCollection<TDestination>();

// IEnumerable extension
public static IEnumerable<TDestination> MapCollection<TDestination>(
    this IEnumerable collection)
{
    foreach (var item in collection)
    {
        yield return Mapper.Map<TDestination>(item);
    }
}

Это приемлемо, но в идеале я хотел бы удалить зависимость TSource врасширение задачи, так как оно не требуется для логики сопоставления.

Проблема

Если я удалю TSource, я не могу заставить компилятор согласиться со мной.Когда я пытаюсь использовать расширение, определенное так:

public static async Task<IEnumerable<TDestination>> MapCollection<TDestination>(
    this Task<IEnumerable> collection)
        => (await collection)
            .MapCollection<TDestination>();

, компилятор выкрикивает:

'Task<IEnumerable<DataServiceModel>>', не содержит определения для 'MapCollection' иЛучшая перегрузка метода расширения 'TaskExtensions.MapCollection<DataViewModel>(Task<IEnumerable>)' требует приемника типа 'Task<IEnumerable>'

Так что я не могу заставить его распознавать мой метод, если нет явного универсального TSource.Я не понимаю, в чем проблема, так как компилятор согласен с моим расширением IEnumerable, которое определено как

MapCollection<TDestination>(this IEnumerable collection)

, но не разрешает:

MapCollection<TDestination>(this Task<IEnumerable> collection)

Вопросы

  1. Можно ли как-то обойти вышеупомянутую проблему и определить мое расширение Task с помощью единственного универсального параметра, который ему действительно нужен?
  2. Представляет ли использование Task проблемы с производительностью?Т.е. нить блокирует, тупики и тд.Я так не думаю, но мне все еще не хватает глубоких знаний в области программирования asnyc.

1 Ответ

1 голос
/ 18 марта 2019

Ваша самая большая проблема - Частичный вывод типа , и это невозможно сделать

Однако, если вы не возражаете против дополнительного звонка, вы можете сойти с рук и Метод расширения и Класс Wrapper

public class Wrapper<TSource>
{
   private readonly Task<IEnumerable<TSource>> _sourceCollection;

   public Wrapper(Task<IEnumerable<TSource>> source) 
      =>_sourceCollection = source;

   public async Task<IEnumerable<TDest>> To<TDest>()
      => (IEnumerable<TDest>)Mapper.Map(await _sourceCollection, _sourceCollection.GetType(), typeof(IEnumerable<TDest>));

}

public static class Extensions
{
   public static Wrapper<TSource> Map<TSource>(this Task<IEnumerable<TSource>> source)
      => new Wrapper<TSource>(source);
}

Использование

await service.GetAllAsync()
             .Map()
             .To<Something>();

Примечание 1 : Это полностью не проверено, и даже если оно работает, не хватает базовых проверок работоспособности

Примечание 2 : Это также немного расточительно с дополнительным слоем асинхронного

...