拿2:使用IDisposable和"使用"作为获取"范围行为"的手段是否滥用?

Cha*_*phs 3 c# exception-handling anti-patterns

TL; DR - 在IDisposable.Dispose中执行业务逻辑是否合适?

在我寻找答案时,我通读了一个问题:使用IDisposable和"使用"作为获取异常安全的"范围行为"的手段是否滥用?它非常接近于解决这个问题,但我想对它进行攻击.我最近遇到了一些看起来像这样的代码:

class Foo : IDisposable
{
    public void Dispose()
    {
        ExecuteSomeBusinessBehavior();
        NormalCleanup();
    }
}
Run Code Online (Sandbox Code Playgroud)

并用于以下环境:

try 
{
    using (var myFoo = new Foo())
    {
        DoStuff();
        foo.DoSomethingFooey();
        ...
        DoSomethingElse();
        Etc();
    }
}
catch (Exception ex)
{
    // Handle stuff
}
Run Code Online (Sandbox Code Playgroud)

看到这段代码后,我立即开始发痒.这是我看到这段代码时看到的内容:

首先,仅查看使用情况,当代码离开使用范围时,实际的业务逻辑(而不仅仅是清理代码)将会被执行,这一点并不明显.

其次,如果"使用"范围内的任何代码抛出异常,则Dispose方法中的业务逻辑仍将执行,并且在Try/Catch可以处理异常之前执行此操作.

我对StackOverflow社区的问题是:将业务逻辑放在IDisposable.Dispose方法中是否有意义?是否有一种模式可以实现类似的结果而不会让我发痒?

Hei*_*nzi 5

(对不起,这更像是评论,但超出了评论长度限制.)

实际上,在.NET框架中有一个示例,其中IDisposable用于创建范围并在处置时执行有用的工作:TransactionScope.

引用TransactionScope.Dispose:

调用此方法标记事务范围的结束.如果TransactionScope对象创建了事务并且在作用域上调用了Complete,则在调用此方法时,TransactionScope对象将尝试提交事务.

如果您决定采取这种方式,我会建议

  • 你明确表示你的对象创建了一个范围,例如,通过调用它FooScope来代替Foo

  • 你会非常认真地思考当异常导致代码离开你的范围时会发生什么.在TransactionScope,Complete块的末尾调用模式确保Dispose可以区分这两种情况.