Преобразование выражения async lambda для делегирования типа System.Func <T>?
У меня есть метод async внутри переносимой библиотеки классов с этой сигнатурой:
private async Task<T> _Fetch<T>(Uri uri)
Он извлекает ресурс, который отбрасывается как конкретный тип T.
Я работаю с библиотекой сторонних кешей (Akavache), которая требует Func<T>
как одного из параметров и имеет попытался сделать это следующим образом:
await this.CacheProvider.GetOrCreateObject<T>(key,
async () => await _Fetch<T>(uri), cacheExpiry);
Это приводит к ошибке:
Невозможно преобразовать выражение async lambda для делегирования типа 'System.Func<T>
'. Асинхронное лямбда-выражение может возвращать void
, Task
или Task<T>
, ни одна из которых не конвертируется в 'System.Func<T>
'.
Я пробовал различные перестановки Func<T>
присваивания без всякой удачи, единственный способ заставить код работать - сделать блокировку Func<T>
:
await this.CacheProvider.GetOrCreateObject<T>(key,
() => _Fetch<T>(uri).Result, cacheExpiry);
который блокирует мое приложение.
Любые указатели на то, где я сбиваюсь с пути?
Ответы
Ответ 1
Нет. Когда кто-то ожидает Func<T> f
, вы можете предположить, что он будет вызван с чем-то вроде result = f()
- то есть он не знает об асинхронном поведении. Если вы обманываете его, используя .Result
, как у вас, он будет тупик в потоке пользовательского интерфейса, потому что он хочет запланировать код после await
(в _Fetch) в потоке пользовательского интерфейса, но вы уже заблокировали его с помощью .Result
.
Асинхронная лямбда может быть передана в Action
, так как она не имеет возвращаемого значения - или Func<Task>
или Func<Task<T>>
.
Посмотрев на ваш случай, GetOrCreateObject
, похоже, вызывает GetOrFetchObject
. Одна из перегрузок GetOrFetchObject
принимает значение Func<Task<T>>
. Вы можете попробовать вызвать этот метод с помощью асинхронной лямбда и посмотреть, помогает ли она.
Ответ 2
Ответ YK1 объясняет, почему вы не можете рассматривать Func<T>
как асинхронный.
Чтобы устранить проблему, используйте GetOrFetchObject
вместо GetOrCreateObject
. Методы "create" предполагают (синхронное) создание, тогда как методы "выборки" работают с (асинхронным) извлечением.
await CacheProvider.GetOrFetchObject<T>(key, () => _Fetch<T>(uri), cacheExpiry)
Я также удалил ненужный async
/await
в вашем лямбда-выражении. Поскольку _Fetch
уже возвращает Task<T>
, нет необходимости создавать async
лямбда, единственной целью которой является await
эта задача.
Ответ 3
Что-то вроде этого?
Public Func<T> ConvertTask<T>(Task<T> task)
{
return ()=>task.Result;
}