- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
在切换到新的 .NET Core 3 的 IAsynsDisposable
期间,我偶然发现了以下问题。
问题的核心:if DisposeAsync
引发异常,此异常隐藏 await using
-block 中引发的任何异常。
class Program
{
static async Task Main()
{
try
{
await using (var d = new D())
{
throw new ArgumentException("I'm inside using");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message); // prints I'm inside dispose
}
}
}
class D : IAsyncDisposable
{
public async ValueTask DisposeAsync()
{
await Task.Delay(1);
throw new Exception("I'm inside dispose");
}
}
捕获的是 DisposeAsync
异常(如果抛出了该异常),并且仅当 DisposeAsync
未抛出时才会捕获 await using
内部的异常扔。
但是,我更喜欢另一种方式:如果可能的话,从 await using
block 获取异常,并且仅当 await using
时才获取 DisposeAsync
-异常code> block 成功完成。
基本原理:想象一下我的类 D
使用一些网络资源并订阅一些远程通知。 await using
中的代码可能会做错事并使通信 channel 失败,之后 Dispose 中尝试正常关闭通信(例如取消订阅通知)的代码也会失败。但第一个异常(exception)给了我有关问题的真实信息,第二个异常(exception)只是次要问题。
在另一种情况下,当主要部分运行并且处理失败时,真正的问题在 DisposeAsync
内部,因此来自 DisposeAsync
的异常是相关的。这意味着仅仅抑制 DisposeAsync
内的所有异常不应该是一个好主意。
我知道非异步情况也存在同样的问题:finally
中的异常会覆盖try
中的异常,这就是为什么不建议抛出 >Dispose()
。但是对于网络访问类来说,在关闭方法中抑制异常看起来并不好。
可以使用以下帮助程序解决该问题:
static class AsyncTools
{
public static async Task UsingAsync<T>(this T disposable, Func<T, Task> task)
where T : IAsyncDisposable
{
bool trySucceeded = false;
try
{
await task(disposable);
trySucceeded = true;
}
finally
{
if (trySucceeded)
await disposable.DisposeAsync();
else // must suppress exceptions
try { await disposable.DisposeAsync(); } catch { }
}
}
}
并像这样使用它
await new D().UsingAsync(d =>
{
throw new ArgumentException("I'm inside using");
});
这有点丑陋(并且不允许在 using block 内提前返回之类的事情)。
是否有一个好的、规范的解决方案,如果可能的话,使用 await using
?我在互联网上搜索甚至没有发现讨论这个问题。
最佳答案
您希望显示一些异常(中断当前请求,或停止进程),并且您的设计预计有时会发生一些异常,您可以处理它们(例如重试并继续)。
但是这两种类型的区别取决于代码的最终调用者 - 这就是异常的全部要点,将决定权留给调用者。
有时,调用者会优先考虑显示原始代码块中的异常,有时会优先考虑 Dispose
中的异常。没有通用规则来决定哪个应该优先。 CLR 在同步和非异步行为之间至少是一致的(正如您所指出的)。
也许不幸的是,现在我们有AggregateException
来表示多个异常,但无法对其进行改造来解决这个问题。即,如果一个异常已经在运行,并且抛出了另一个异常,那么它们将被组合成一个 AggregateException。可以修改catch
机制,以便如果您编写catch (MyException)
,那么它将捕获任何包含类型异常的
。不过,这个想法还带来了各种其他并发症,而且现在修改如此基本的东西可能风险太大。AggregateException
>MyException
您可以改进 UsingAsync
以支持提前返回值:
public static async Task<R> UsingAsync<T, R>(this T disposable, Func<T, Task<R>> task)
where T : IAsyncDisposable
{
bool trySucceeded = false;
R result;
try
{
result = await task(disposable);
trySucceeded = true;
}
finally
{
if (trySucceeded)
await disposable.DisposeAsync();
else // must suppress exceptions
try { await disposable.DisposeAsync(); } catch { }
}
return result;
}
关于c# - 处理 DisposeAsync 中异常的正确方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58954018/
我不认为这个问题与 "Proper way to deal with exceptions in DisposeAsync" 重复。 假设我的类实现了 IAsynsDisposable,因为它有一个长
在切换到新的 .NET Core 3 的 IAsynsDisposable 期间,我偶然发现了以下问题。 问题的核心:if DisposeAsync引发异常,此异常隐藏 await using-blo
我正在编写一种将单独的文本行异步写入文件的方法。如果它被取消,它会删除创建的文件并跳出循环。 这是工作正常的简化代码...我标记了 2 点,我不确定它们是如何处理的。我希望代码在任何情况下都不会阻塞线
考虑以下摘自 Microsoft docs 的代码: using FileStream createStream = File.Create(fileName); // ...write to str
我是一名优秀的程序员,十分优秀!