Как получить исключение ValueTask? - PullRequest
0 голосов
/ 22 октября 2018

В проекте предстоящего C # 8 IAsyncEnumerable используются ValueTask и ValueTask<T> для передачи потенциально синхронных результатов обратно логике потребителя.Они оба имеют свойство IsFaulted, но в отличие от Task, свойство Exception отсутствует.

Возможно ли даже иметь ValueTask, который не содержит нормальный Task инаходится в состоянии сбоя или отменено?

Документация ValueTask<T>.Result указывает на то, что при вызове ее при неудачной задаче будет сброшено содержимое Exception.Будет ли следующий код иметь смысл извлекать Exception?

IAsyncEnumerable<int> asyncSequence = ...

ValueTask<bool> valueTask = asyncSequence.MoveNextAsync();

if (valueTask.IsFaulted) {
    // this has to work in a non-async method
    // there is no reason to block here or use the
    // async keyword
    try {
        var x = valueTask.Result;
    } catch (Exception ex) {
        // work with the exception
    }
}

ValueTask endTask = asyncSequence.DisposeAsync();

if (endTask.IsFaulted) {
    // there is no ValueTask.Result property
    // so the appoach above can't work
}

Не универсальный ValueTask не имеет свойства Result.Как я могу извлечь Exception тогда?

Как правило, я предполагаю, что применение AsTask может быть использовано для обоих извлечений, однако, я думаю, что это влечет за собой выделение, что делает использование ValueTask сомнительным впервое место, как я понимаю.

Ответы [ 3 ]

0 голосов
/ 22 октября 2018

Обычный способ блокировки до завершения Task или Task<T> - это вызов метода Task.Wait() .

Если выброшено исключение, оно будетSystem.AggregatedException.Свойство InnerExceptions будет содержать коллекцию исключений, вызвавших текущее исключение.

Начиная с .NET Framework 4.5 и .NET Core 1.0 также существует метод GetAwaiter(), где вы можете вызвать GetResult() для его возвращаемого значения и сгенерировать первое исключение в коллекции.

Но вы никогда не должны этого делать !!!

Вы должны сделать это:

// this has to work in a non-async method
try {
    var x = await valueTask;
} catch (Exception ex) {
    // work with the exception
}

ValueTask и ValueTask<T> используются, чтобы избежать выделения кучи, когда, возможно, результат уже доступен.Это не значит, что блокировать эту задачу безопасно.

0 голосов
/ 23 октября 2018

Ответ corefx team указывает, что это действительно невозможно напрямую и не может быть легко добавлено из-за необходимости изменить сопутствующий интерфейс, что может привести к осложнениям.

* 1004Обходной путь предложил, как я и предполагал, использовать AsTask для получения Exception.
IAsyncEnumerable<int> asyncSequence = ...

ValueTask<bool> valueTask = asyncSequence.MoveNextAsync();

if (valueTask.IsFaulted) {
    var ex = valueTask.AsTask().Exception;
    // work with the exception
}

ValueTask endTask = asyncSequence.DisposeAsync();

if (endTask.IsFaulted) {
    var ex = valueTask.AsTask().Exception;
    // work with the exception
}
0 голосов
/ 22 октября 2018

Лучше всего было бы использовать оператор try и попытаться поймать исключение, а затем обработать его позже ... Что касается ValueTask, который не выполняет обычную задачу, я думаю, что вы будетевозможность использовать лямбда-методы для решения этой проблемы.

try {
    var x = Task.Run(()=>{ ... });
}
catch (Exception ex) {
    // Do something with exception.
}

Или в любом случае для ValueTask.Учитывая то, что в этих прошлых сборках C # уделял много внимания асинхронным задачам, можно с уверенностью сказать, что вы будете использовать лямбду и вызовы событий.

private void foo(ValueTask task) {
        lock (threadObj) {
            var x = Task.Run(()=> { return task.doWork(); }
            if (x == true) {
                // then do other work...
            }
            else {
                // handle 'exception'...
            }
        }
}
...