Хорошей особенностью параметров out
является то, что они могут использоваться для возврата данных, даже если функция генерирует исключение. Я думаю, что самым близким эквивалентом этого метода с помощью метода async
будет использовать новый объект для хранения данных, которые могут ссылаться как на метод async
, так и на вызывающий. Другим способом было бы передать делегат, как предложено в другом ответе .
Обратите внимание, что ни один из этих методов не будет иметь какого-либо принудительного исполнения от компилятора, который out
имеет , Т.е. компилятор не потребует установки значения для общего объекта или вызова переданного в делегате.
Вот пример реализации с использованием общего объекта для имитации ref
и out
для использования с методами async
и другими различными сценариями, где ref
и out
недоступны:
class Ref
{
// Field rather than a property to support passing to functions
// accepting `ref T` or `out T`.
public T Value;
}
async Task OperationExampleAsync(Ref successfulLoopsRef)
{
var things = new[] { 0, 1, 2, };
var i = 0;
while (true)
{
// Fourth iteration will throw an exception, but we will still have
// communicated data back to the caller via successfulLoopsRef.
things[i] += i;
successfulLoopsRef.Value++;
i++;
}
}
async Task UsageExample()
{
var successCounterRef = new Ref();
// Note that it does not make sense to access successCounterRef
// until OperationExampleAsync completes (either fails or succeeds)
// because there’s no synchronization. Here, I think of passing
// the variable as “temporarily giving ownership” of the referenced
// object to OperationExampleAsync. Deciding on conventions is up to
// you and belongs in documentation ^^.
try
{
await OperationExampleAsync(successCounterRef);
}
finally
{
Console.WriteLine($"Had {successCounterRef.Value} successful loops.");
}
}