#c# #asynchronous #dynamic #task #continuewith
#c# #асинхронный #динамический #задача #continuewith
Вопрос:
У меня есть метод, который получает a Task<T>
, где T неизвестно во время компиляции, и an IAsyncDisposable
. Мне нужно вернуть a Task<T>
, который автоматически удаляет одноразовый объект после завершения исходной задачи.
Это то, что я придумал до сих пор, но это выдает ошибку времени компиляции
private static TResult AutoDispose<TResult>(TResult result, IAsyncDisposable asyncDisposable)
{
Func<dynamic, dynamic> continuationFunction = async t => { await asyncDisposable.DisposeAsync(); return ((dynamic)t).Resu< };
var autoDisposing = ((dynamic)result).ContinueWith(continuationFunction);
return (TResult)autoDisposing;
}
Ошибка, которую я получаю, это
Не удается преобразовать асинхронное лямбда-выражение в тип делегирования ‘Func<динамический, динамический>’. Асинхронное лямбда-выражение может возвращать void, Task или Task, ни один из которых не преобразуется в ‘Func<динамический, динамический>’.
Я уже пробовал разные комбинации dynamic
и Task
, но не смог создать рабочее решение. Я всегда получаю ошибки компиляции или времени выполнения.
Редактировать
Потому что кажется непонятным, почему я делаю это таким образом:
Я использую это внутри IAsyncQueryProvider
s ExecuteAsync
-метода. Интерфейс определяет сигнатуру методов следующим образом
public TResult ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken = default)
Исходя из этого, я знаю TResult
, что это либо тип IAsyncEnumerable<T>
, либо Task<T>
. Я уже написал код для обработки случая, когда это an IAsyncEnumerable<T>
, но я все еще борюсь, когда это a Task<T>
.
Комментарии:
1. Пожалуйста, опубликуйте пример того, где вы используете свой
AutoDispose
метод.2. Вообще говоря, смешивать
dynamic
с дженериками — плохая идея. Это очень разные вещи. Я думаю, что этого лучше избегатьdynamic
полностью, потому что это в первую очередь сводит на нет смысл использования статически типизированного языка, такого как C #.3. » T неизвестно во время компиляции и an «, я на самом деле не могу пройти мимо этого утверждения, оно кажется довольно неправильным. Дженерики компилируются во время компиляции, они ДОЛЖНЫ быть известны.
4. @TheGeneral
T
неизвестно во время компиляции, если вы создаете библиотеку с открытыми обобщениями.5. @Dai означает несвязанный универсальный тип ? Однако они не могут использоваться ни в каком выражении, кроме
typeof
… Редактировать… ах, хорошо, отмените это, я понимаю, о чем вы говорите. хороший момент. 🙂
Ответ №1:
Для использования async
тип результата во время компиляции должен быть Task
(или похожий на задачу). Вложенные задачи обычно используются ContinueWith
с async
продолжениями; Unwrap
это одно из решений. Если вы можете полностью избежать ContinueWith
этого, это еще лучше, но я считаю, что в этом случае это потребует довольно утомительной работы с дженериками.
Что-то вроде этого должно работать:
private static TResult AutoDispose<TResult>(TResult result, IAsyncDisposable asyncDisposable) // where TResult: Task<T>
{
Func<dynamic, Task<TResult>> continuationFunction = async () => { await asyncDisposable.DisposeAsync(); return resu< };
var continuation = ((dynamic)result).ContinueWith(continuationFunction, TaskScheduler.Default);
var newResult = TaskExtensions.Unwrap(continuation);
return (TResult)newResu<
}
Ответ №2:
Попробуйте это?
private static async Task<TResult> AutoDispose<TResult>( this Task<TResult> task )
where TResult : IAsyncDisposable
{
TResult result = await task.ConfigureAwait(false);
if( result != null )
{
await result.DisposeAsync().ConfigureAwait(false);
}
return resu<
}
Пример использования:
Task<HttpResponseMessage> task = new HttpClient()
.GetAsync( "/foo" )
.AutoDispose();
HttpResponseMessage resp = await task;
// `resp` will be in a disposed state at this point.
Комментарии:
1.
AutoDispose
Метод не может быть асинхронным и должен возвращатьTResult
, аTask<TResult>
также неTResult
имеет типаTask<T>
, поэтому его перенос приведет к чему-то вродеTask<Task<T>>
. Я использую это внутриExecute
метода AsyncQueryProviders, поэтому у меня есть эти ограничения.