Я хочу написать асинхронный метод с out
параметром, например так:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Как мне это сделать GetDataTaskAsync
?
источник
Я хочу написать асинхронный метод с out
параметром, например так:
public async void Method1()
{
int op;
int result = await GetDataTaskAsync(out op);
}
Как мне это сделать GetDataTaskAsync
?
Вы не можете иметь асинхронные методы с параметрами ref
или out
.
Лучиан Висчик объясняет, почему это невозможно в этом потоке MSDN: http://social.msdn.microsoft.com/Forums/en-US/d2f48a52-e35a-4948-844d-828a1a6deb74/why-async-methods-cannot-have -REF или-Out-параметры
Что касается того, почему асинхронные методы не поддерживают параметры вне ссылки? (или параметры ref?) Это ограничение CLR. Мы решили реализовать асинхронные методы аналогично методам итераторов - т.е. с помощью компилятора, преобразующего метод в объект конечного автомата. В CLR нет безопасного способа сохранить адрес «выходного параметра» или «ссылочного параметра» в качестве поля объекта. Единственный способ поддерживать параметры по ссылке - это если асинхронная функция выполнялась посредством перезаписи CLR низкого уровня вместо перезаписи компилятором. Мы изучили этот подход, и он многое сделал для этого, но в конечном итоге он был бы настолько дорогостоящим, что никогда бы не произошло.
Типичный обходной путь для этой ситуации - вместо этого асинхронный метод возвращает кортеж. Вы можете переписать свой метод так:
public async Task Method1()
{
var tuple = await GetDataTaskAsync();
int op = tuple.Item1;
int result = tuple.Item2;
}
public async Task<Tuple<int, int>> GetDataTaskAsync()
{
//...
return new Tuple<int, int>(1, 2);
}
Tuple
альтернативу. Очень полезно.Tuple
. : PВы не можете иметь
ref
илиout
параметры вasync
методах (как уже было отмечено).Это кричит о некотором моделировании данных, перемещающихся:
Вы получаете возможность многократно использовать свой код, плюс он более читабелен, чем переменные или кортежи.
источник
Решением C # 7 + является использование неявного синтаксиса кортежей.
возвращаемый результат использует сигнатуру метода, определяющую имена свойств. например:
источник
Алекс сделал большой акцент на удобочитаемости. Эквивалентно, функция также достаточно интерфейса, чтобы определить тип (ы), которые возвращаются, и вы также получите значимые имена переменных.
Вызывающие операторы предоставляют лямбда (или именованную функцию) и подсказки intellisense, копируя имена переменных из делегата.
Этот конкретный подход похож на метод Try, который
myOp
устанавливается, если результат метода равенtrue
. Иначе тебя не волнуетmyOp
.источник
Приятной особенностью
out
параметров является то, что они могут использоваться для возврата данных, даже когда функция выдает исключение. Я думаю, что самым близким эквивалентом выполнения этогоasync
метода будет использование нового объекта для хранения данных, на которыеasync
могут ссылаться как метод, так и вызывающая сторона. Другой способ - передать делегата, как это предлагается в другом ответе. .Обратите внимание, что ни один из этих методов не будет иметь никакого вида принудительного применения от компилятора, который
out
имеет. Т.е. компилятор не потребует от вас установки значения для общего объекта или вызова переданного делегата.Вот пример реализации с использованием общего объекта для имитации
ref
иout
для использованияasync
методов и других различных сценариев , в которыхref
иout
не доступны:источник
Я люблю
Try
шаблон. Это аккуратный образец.Но это сложно
async
. Это не значит, что у нас нет реальных вариантов. Вот три основных подхода, которые вы можете рассмотреть дляasync
методов в квази-версииTry
шаблона.Подход 1 - вывести структуру
Это больше похоже на
Try
метод синхронизации, возвращающий только atuple
вместо параметраbool
сout
параметром, который, как мы все знаем, недопустим в C #.С методом , который возвращается
true
изfalse
и никогда не бросаетexception
.Подход 2 - передать методы обратного вызова
Мы можем использовать
anonymous
методы для установки внешних переменных. Это умный синтаксис, хотя и немного сложный. В небольших дозах это нормально.Метод подчиняется основам
Try
шаблона, но устанавливаетout
параметры для передачи в методах обратного вызова. Это сделано так.Подход 3 - используйте ContinueWith
Что делать, если вы просто используете
TPL
как задумано? Нет кортежей. Идея в том, что мы используем исключения для перенаправленияContinueWith
на два разных пути.С методом, который выбрасывает,
exception
когда есть какой-либо сбой. Это отличается от возвращенияboolean
. Это способ общения сTPL
.В приведенном выше коде, если файл не найден, создается исключение. Это вызовет сбой,
ContinueWith
который будет обрабатыватьсяTask.Exception
в его логическом блоке. Аккуратно, а?Удачи.
источник
ContinueWith
вызовов имеет ожидаемый результат? Насколько я понимаю, второйContinueWith
проверит успешность первого продолжения, а не исходную задачу.У меня была та же проблема, что и при использовании шаблона Try-method-pattern, который в принципе кажется несовместимым с async-await-paradigm ...
Для меня важно, что я могу вызывать метод Try в одном предложении if, и мне не нужно предварительно определять переменные out, но я могу сделать это in-line, как в следующем примере:
Поэтому я пришел к следующему решению:
Определите вспомогательную структуру:
Определите асинхронный Try-метод следующим образом:
Вызовите асинхронный Try-метод следующим образом:
Для параметров множественного выхода вы можете определить дополнительные структуры (например, AsyncOut <T, OUT1, OUT2>) или вы можете вернуть кортеж.
источник
Ограничение
async
методов, не принимающихout
параметры, распространяется только на сгенерированные компилятором асинхронные методы, которые объявлены сasync
ключевым словом. Это не относится к созданным вручную асинхронным методам. Другими словами, можно создаватьTask
возвращающие методы, принимающиеout
параметры. Например, допустим, у нас уже естьParseIntAsync
метод, который выбрасывает, и мы хотим создать метод,TryParseIntAsync
который не выбрасывает. Мы могли бы реализовать это так:Использование метода
TaskCompletionSource
andContinueWith
немного неудобно, но другого варианта нет, так как мы не можем использовать удобноеawait
ключевое слово внутри этого метода.Пример использования:
Обновление: если асинхронная логика слишком сложна, чтобы ее можно было выразить
await
, то она может быть заключена во вложенный асинхронный анонимный делегат.TaskCompletionSource
все еще будет необходим дляout
параметра. Возможно, чтоout
параметр мог быть завершен до завершения основной задачи, как в примере ниже:В этом примере предполагается существование трех асинхронных методов
GetResponseAsync
,GetRawDataAsync
иFilterDataAsync
которые называются последовательно.out
Параметр завершаются по завершению второго метода.GetDataAsync
Метод может быть использован , как это:В этом упрощенном примере важно дождаться
data
ожидания перед ожиданиемrawDataLength
, потому что в случае исключенияout
параметр никогда не будет завершен.источник
Я думаю, что использование ValueTuples, как это может работать. Вы должны сначала добавить пакет ValueTuple NuGet:
источник
Вот код ответа @ dcastro, модифицированный для C # 7.0 с именованными кортежами и деконструкцией кортежей, что упрощает запись:
Для получения подробной информации о новых именованных кортежах, литералах кортежей и деконструкциях кортежей см .: https://blogs.msdn.microsoft.com/dotnet/2017/03/09/new-features-in-c-7-0/
источник
Вы можете сделать это с помощью TPL (библиотека параллельных задач) вместо прямого, используя ключевое слово await.
источник