【问题标题】:Refactoring: using statement without scope, when does the implicit `Dispose` call happen?重构:使用没有范围的语句,隐式的“Dispose”调用何时发生?
【发布时间】:2020-04-04 16:33:35
【问题描述】:

前几天我正在重构一些东西,我遇到了这样的事情:

public async Task<Result> Handle(CancelInitiatedCashoutCommand command, CancellationToken cancellationToken)
{
    using (_logger.BeginScope("{@CancelCashoutCommand}", command))
    {
        return await GetCashoutAsync(command.CashoutId)
            .Bind(IsStatePending)
            .Tap(SetCancelledStateAsync)
            .Tap(_ => _logger.LogInformation("Cashout cancellation succeeded."));
    }
}

ReSharper 建议将其重构为:

public async Task<Result> Handle(CancelInitiatedCashoutCommand command, CancellationToken cancellationToken)
{
    using var scope = _logger.BeginScope("{@CancelCashoutCommand}", command);
    return await GetCashoutAsync(command.CashoutId)
        .Bind(IsStatePending)
        .Tap(SetCancelledStateAsync)
        .Tap(_ => _logger.LogInformation("Cashout cancellation succeeded."));
}

我有点怀疑,实际上我不确定第二个版本何时会发生隐式Dispose 调用。

我怎么知道?

【问题讨论】:

  • using var scope = ... ; 表示在离开Handle 范围时scope 将是Disposed
  • 所以基本上包含该语句的方法。
  • 你看过the documentation吗?如果是这样,有什么不清楚的地方?顺便说一句,您总是可以通过实现自己的测试类public class TestDispose : IDisposable { public void Dispose(){ Console.WriteLine("disposing"); }} 来测试它,以查看何时调用输出。
  • 对于诸如日志记录范围和事务之类的事情,如果范围仍然用块明确指示,代码可能会更清晰,因为通常不命名日志记录范围。 using var 很有用,如果从功能上讲,您并不真正关心资源何时被释放,只要它发生(例如SqlConnection)。在所有情况下,Dispose 时刻都是确定性的,但对于using var,当它不是特别重要时,可以不说范围。当然,这是主观的,这就是 Resharper 坚持建议的原因。
  • 我确实检查了文档,但它看起来很奇怪,感觉很不对劲。我自己也检查过,是的,在调用 dispose 之后,但我不确定编译器是否可以在其他一些情况下更改重写(和隐式 Dispose 调用)

标签: c# .net-core dispose using-statement


【解决方案1】:

Resharper 建议 C# 8.0 using declaration 功能:

 public async Task<Result> Handle(CancelInitiatedCashoutCommand command, 
                                  CancellationToken cancellationToken)
 {  
    using var scope = ...;
    ...
 } // <- scope will be Disposed on leaving its scope (here on Handle method's scope)

【讨论】:

    【解决方案2】:

    那是一个 C#8 using statement,当变量本身超出范围时,scope 引用的对象被释放。

    在这种情况下,那将是在您的 Task 完成之后。

    【讨论】:

      【解决方案3】:

      我也在想同样的事情。 using 声明在方法结束时移出范围,然后才被释放。 Microsoft docs states以下:

      文件在到达方法的右大括号时被释放。这就是声明文件的范围的结尾。

      看起来如果你有一个 using 语句,它会在 using 大括号的末尾处理变量,而不是只在方法末尾处理变量的 using 声明。如果您在 watch 或 locals 窗口中查看此内容,您将立即看到它超出范围。 https://dirkstrauss.com/c-sharp-8-0-using-declarations/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-04-19
        • 1970-01-01
        • 2014-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-08-11
        • 2010-11-05
        相关资源
        最近更新 更多