将同步代码转换为异步代码未处理 System.OperationCanceledException:'The operation was canceled.'

Converting sync to async code got unhandled System.OperationCanceledException: 'The operation was canceled.'

我正在尝试将我的同步功能转换为异步功能。在我所有的同步函数中,我都有一个用于函数、任务和并行块的取消标记。在调用异步函数之前我有一个 try/catch 块,但我遇到了一个未处理的异常:

Exception thrown: 'System.OperationCanceledException' in System.Threading.Tasks.Parallel.dll An exception of type 'System.OperationCanceledException' occurred in System.Threading.Tasks.Parallel.dll but was not handled in user code The operation was canceled.

我的异步函数:

public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
            await Task.Run(() => Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);

我怎么称呼它:

try
        {
            await SlicerFile.DecodeAsync(fileName, fileDecodeType, Progress);
        }
        catch (OperationCanceledException) { } // Do not work!
        catch (Exception exception) // Works for other exceptions
        {
            await this.MessageBoxError(exception.ToString(), "Error opening the file");
        }

catch (OperationCanceledException) 不会在取消事件中达到,也不会达到 catch (Exception exception)。由于我的尝试是最重要的,为什么它没有捕获到异常?

但如果我这样做:

public async Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) =>
            await Task.Run(() => throw new Exception("Test"));

我得到了通用异常的异常捕获(已处理)

另一方面,旧代码可以正常工作并处理 OperationCanceledException:

var task = await Task.Factory.StartNew( () =>
        {
            try
            {
                SlicerFile.Decode(fileName, fileDecodeType, Progress);
                return true;
            }
            catch (OperationCanceledException) {} // Works!
            catch (Exception exception) 
            {
                Dispatcher.UIThread.InvokeAsync(async () =>
                    await this.MessageBoxError(exception.ToString(), "Error opening the file"));
            }

            return false;
        });

我做错了什么?

Task.Run 的结果不一定需要在那里等待。您可以只 return 运行 任务,然后该方法不再需要等待或异步。

    Task DecodeAsync(string? fileFullPath, FileDecodeType fileDecodeType, OperationProgress? progress = null) => Task.Run(() => 
Decode(fileFullPath, fileDecodeType, progress), progress?.Token ?? default);

并且由于您正在传递一个令牌,您可以监视它以干净地退出解码方法,而不是试图捕获并忽略操作取消的异常。

如果可以的话,将解码方法本身设为异步会更好。它已经 return 是一个任务,所以它可以 return 一个任务(或其他)。您的旧代码也以同样的方式异步,因此我可以看到您的新代码没有任何优势。