Преобразования асинхронных лямбда-выражение в делегат типа System.Фанк?

у меня есть асинхронный метод в переносимая библиотека классов с этой подписью:

private async Task<T> _Fetch<T>(Uri uri)

он извлекает ресурс, который отбрасывается как конкретный тип T.

Я работаю с сторонней библиотекой кэша (Akavache), что требует Func<T> в качестве одного из параметров и попытались сделать это таким образом:

await this.CacheProvider.GetOrCreateObject<T>(key,
    async () => await _Fetch<T>(uri), cacheExpiry);

это приводит к ошибке:

не удается преобразовать лямбда-выражение в делегат асинхронного тип '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); 

который блокирует мое приложение.

есть указания, где я сбиваюсь с пути?

3 ответов


не могу. Когда кто-то ожидает Func<T> f вы можете предположить, что он будет вызван, с чем-то вроде result = f() - т. е. он не знает об асинхронном поведении. Если вы обманываете его с помощью .Result как у вас есть-это будет взаимоблокировка в потоке пользовательского интерфейса, потому что он хочет запланировать код после await (в _Fetch) в потоке пользовательского интерфейса, но вы уже заблокировали его с помощью .Result.

асинхронная лямбда может быть передана в Action поскольку он не имеет возвращаемого значения - или Func<Task> или Func<Task<T>>.

глядя на ваш случай,GetOrCreateObject кажется, вызывает GetOrFetchObject. Один из GetOrFetchObject перегрузки принимает Func<Task<T>>. Вы можете попробовать вызвать этот метод с помощью асинхронной лямбды и посмотреть, поможет ли это.


YK1 это объясняет, почему вы не можете относиться к Func<T> как асинхронный.

чтобы устранить проблему, используйте GetOrFetchObject вместо GetOrCreateObject. Методы " create "предполагают (Синхронное) создание, в то время как методы" fetch " работают с (асинхронным) извлечением.

await CacheProvider.GetOrFetchObject<T>(key, () => _Fetch<T>(uri), cacheExpiry)

я также удалил ненужное async/await в лямбда-выражение. С _Fetch возвращает Task<T>, нет необходимости создавать элемент async лямбда, чья единственная цель это await этой задачи.


что-то вроде этого?

 Public Func<T> ConvertTask<T>(Task<T> task)
 {
     return ()=>task.Result;
 }