C# 异步世界中的故障保护处理

C# 异步世界中的故障保护处理,c#,idisposable,C#,Idisposable,在同步世界中,C#使所有一次性物品的管理变得非常简单: using(IDisposable someDisposable=bla.bla()) { //do our bidding } //don't worry too much about it 然而,当我们使用异步时,我们不再方便地使用块。我遇到的最好的策略之一是,它允许我们使用异步代码“就好像它是同步的”。这意味着我们可以在迭代器处理程序中使用块来保持我们的,而不会陷入何时处理和捕获所有需要处理的情况的复杂决策中 然而,在许多

在同步世界中,C#使所有一次性物品的管理变得非常简单:

using(IDisposable someDisposable=bla.bla())
{
     //do our bidding
}
//don't worry too much about it
然而,当我们使用异步时,我们不再方便地使用
块。我遇到的最好的策略之一是,它允许我们使用异步代码“就好像它是同步的”。这意味着我们可以在迭代器处理程序中使用
块来保持我们的
,而不会陷入何时处理和捕获所有需要处理的情况的复杂决策中

然而,在许多情况下,调用CCR似乎有些过分,老实说,尽管我对CCR很满意,但对于不熟悉CCR的人来说,它可能看起来像是双重负担


所以我的问题是:当一次性对象必须保持在当前范围之外时,还有什么其他策略可以用于管理自己的IDisposable?

一种方法是让所有无法与处置方法共存的方法在运行时锁定,完成后,检查队列中是否有需要处理的对象。然后,处置方法可以将自身添加到队列中,使用TryEnter尝试获取锁,处置对象并在成功时将其从队列中删除,或者让锁的当前持有者处理处置。

事实证明,这个问题也在语言设计者的脑海中

现在,这个问题的正确答案是使用基于
任务
的异步API版本,该版本已为几乎所有异步操作提供,再加上新的C#
async
/
wait
关键字。这使我们能够在异步操作的生命周期内保持所有内容的作用域:

async Task<int> DoSomething()
{
    using(var foo = new SomeDisposableThing())
    {
         await foo.DoSomethingAsync();
    }
    return 0;
}
异步任务DoSomething()
{
使用(var foo=newsomedisposablething())
{
等待foo.DoSomethingAsync();
}
返回0;
}

问得好。我只是发布这条评论,以便我能再次找到它。@MusiGenesis:将问题“收藏”以便于查找是否更有意义?@Gabe:我该如何记得去查看我的收藏?回拨怎么办?在处理之前必须完成的代码甚至可能在其他事件发生之前都不会运行。@Ben Voigt:我假设有人知道某个特定项目何时不再需要。使异步dispose变得棘手的不是与正在处理的对象同时执行或挂起操作的可能性,而是对将受dispose影响的实体同时执行的操作。例如,假设有一个数据库使用单个数据流进行通信;为不同的连接分配ID号,每个命令或响应都包含连接ID。如果在线程想要关闭连接时发送命令…@Ben Voigt:…则“close”命令必须等待。根据具体情况,Dispose最好等到关闭完成,这样才能知道它是否工作,但如果这可能需要一段时间,Dispose最好将close命令排队并立即返回。关键是,重要的不是使用连接对象的多个线程,而是使用数据流的多个线程。