Ожидание async Задача без обертывания исключений в AggregateException - программирование
Подтвердить что ты не робот

Ожидание async Задача без обертывания исключений в AggregateException

Я использую библиотеку, которая предоставляет методы, заканчивающиеся на ...Async, и возвращает Task. Я собираюсь использовать их в приложении командной строки. Поэтому мне нужно их синхронно называть.

С#, конечно, не позволяет вызывать эти методы в методе Main, так как вы не можете использовать модификатор async по методу Main. Предположим, что это задача:

var task = datastore.Save(data);

Я нашел несколько решений вроде:

Tasks.WaitAll(task);
task.Wait();

однако все эти обматывающие исключения исключены в AggregateException, Я не хочу этого. Я просто хочу сказать task.Result, и я ожидаю, что будет выбрано исходное исключение.

Когда я использую метод, возвращающий Task<TResult>, task.Result throws AggregateException, даже если не заданы задачи продолжения. Почему это происходит?

Я также пробовал,

task.RunSynchronously();

он дает ошибку:

RunSynchronously не может быть вызван задачей, не связанной с делегатом, такой как задача, возвращенная из асинхронного метода.

поэтому я предполагаю, что не для методов, помеченных как async.

Любые идеи о шаблонах с использованием библиотек, предназначенных для асинхронных приложений в консольных приложениях, где нет асинхронного контекста?

4b9b3361

Ответ 1

  Я собираюсь использовать их в приложении командной строки. Поэтому мне нужно много раз им звонить.

Нет, ты не Вы можете использовать async - await в консольном приложении, вам просто нужно сделать асинхронный переход для синхронизации на самом верху. И вы можете сделать это, используя Wait():

public static void Main()
{
    MainAsync().Wait();
}

public static async Task MainAsync()
{
    var datastore = …;
    await datastore.SaveAsync();
}

Обычно объединение await с Wait() является плохой идеей (она может вызвать взаимные блокировки), но здесь это правильное решение.

Обратите внимание, что если SaveAsync() выдает исключение, и вы его не перехватываете, оно будет переброшено как AggregateException из Wait(). Но вы можете поймать его как исходное исключение в MainAsync() (потому что он не использует Wait()).

Если вы действительно хотите получить первое исключение напрямую, вы можете сделать что-то похожее на то, что делает await: task.GetAwaiter().GetResult(). Обратите внимание, что если Task содержит более одного исключения, вы получите только первое (но то же самое относится и к await).

Начиная с С# 7.1, вы можете сделать свой метод Main async, и компилятор напишет код перехода для вас:

public static async Task Main()
{
    var datastore = …;
    await datastore.SaveAsync();
}

Когда я использую метод, возвращающий Task<TResult>, task.Result выбрасывает AggregateException, даже если не заданы задачи продолжения. Почему это происходит?

Это не имеет ничего общего с продолжениями. Один Task может представлять несколько операций, и каждая из них может выдать исключение. Из-за этого методы Task всегда выдают исключения, заключенные в AggregateException.

Я также попробовал task.RunSynchronously()

В этом нет смысла. RunSynchronously() можно использовать только на Task, которые были созданы с помощью конструктора Task. Это не тот случай, поэтому вы не можете его использовать. Task, возвращаемый из асинхронных методов, всегда уже запущен.

Ответ 2

Вы можете создать фиктивный Main

public static void Main()
{
    MainAsync().Wait();
}

public static async Task MainAsync()
{
    try {
        var result = await dataStore.Save(data);
    } catch(ExceptionYouWantToCatch e) {
       // handle it
    }
}

Также см. этот ответ: fooobar.com/questions/27260/...

Ответ 3

Начиная с С# 7.1 теперь вы можете объявить метод Main как асинхронный. Просто убедитесь, что для вашего языка установлена основная версия по умолчанию (которая теперь должна работать в VS 2019), или вы всегда можете выбрать конкретную версию языка.

Смотрите эту ссылку для деталей. Включите асинхронный основной