【问题标题】:When does IDE0063 dispose?IDE0063 什么时候处理?
【发布时间】:2019-08-12 11:08:23
【问题描述】:

我正在尝试理解这个 C# 8 简化功能:

IDE0063 'using' 语句可以简化

例如,我有:

void Method()
{
    using (var client = new Client())
    {
        // pre code...
        client.Do();
        // post code...
    } --> client.Dispose() was called here.
    // more code...
}

IDE 告诉我,我可以通过编写以下代码来简化 using 语句:

void Method()
{
    using (var client = new Client());
    // pre code...
    client.Do();
    // post code...
    // more code...
}

我无法理解它是如何工作的,以及它如何决定我不再是 using 变量。更具体地说,它究竟是什么时候调用client.Dispose 方法的?

【问题讨论】:

    标签: c# ide refactoring c#-8.0


    【解决方案1】:

    您使用的是 C# 8。在较旧的 C# 版本中,; 会使其无效。

    在新语法中,client 保留在周围方法的范围内(或其他 {} 范围块)。请注意,您也可以省略外部的 () 对。

    这叫做using声明,文档是here

    void Method()
    {
        using var client = new Client();
        // pre code...
        client.Do();
        // post code...
        // more code...
    } --> client.Dispose() is called here (at the latest)
    

    从逻辑上讲,Dispose 发生在},但优化器可能会更早完成。

    编辑

    我注意到 // more codeusing 块的末尾之后会阻止这种改进的出现。所以如果你转换下面的代码就不会再有歧义了:

    void Method()
    {
        // not relevant code
    
        using (var client = new Client())
        {
            // pre code...
            client.Do();
            // post code...
        }
    }
    

    进入这段代码:

    void Method()
    {
        // not relevant code
    
        using var client = new Client();
        // pre code...
        client.Do();
        // post code...
    }
    

    【讨论】:

    • 所以 OP 全力以赴,然后完全忽略了所写的内容并提出新问题,甚至犯了一个错误(他的第二个片段仍在使用语句)?
    • 所以 IDE 建议简化实际上将处理推迟到“更多代码...”的末尾是错误的?
    • @Holger - 你说得有道理,但这并不重要。遵循短方法等的标准做法。这样做的动机是减少混乱(考虑在一个范围内使用 3 或 4 次使用)。
    • 我一般不反对该功能。但我理解当 IDE 提出建议时 OP 的困惑,就好像这两个代码 sn-ps 是等价的。
    • 嗯,我不喜欢这样...简化可能会在以后导致重大更改。也许这是应该成为避免编码标准的事情之一?类似于故意为 if 语句使用大括号 (?)
    【解决方案2】:

    简短的回答是新的(可选)using 语句语法继承了它的 父级 范围。

    我必须同意 OP 的观点,即这是 C# 8.0 中一个非常令人困惑的变化,原因有很多。

    从历史上看,using 一直像其他块一样使用作用域(ifswitch 等)。和if 一样,using 语句的范围是代码的下一行或块

    所以写这样的东西是完全有效的:

    using (var client = new Client())
        client.Do();
    

    这意味着client 仅在单个语句的范围内,这对于单行操作非常有用,例如触发没有返回值的 SQL 存储过程。

    但现在我们也有:

    using var client = new Client();
    client.Do();
    

    这根本不是一回事; client 仍然在整个方法的范围内。

    现在,Visual Studio 只会在您原来的 using 块之后没有任何内容的情况下建议此更改,因此它在功能上是相同的。但是,如果稍后添加更多代码怎么办?使用旧的范围表示法,新代码是在范围内还是在范围外是非常清楚的。使用新语法,using 之后的所有内容都在范围内,但这可能不清楚。

    Roslyn 团队可能认为这并不重要。与流控制语句(if 等)不同,您真的关心您的对象是否在范围内保留更多代码行吗?可能不是。但就像所有事情一样,这取决于。

    在某些方面,这是一种改进,因为它清楚地表明,“实例化这个对象并在它超出范围时调用Dispose()。”当对象超出范围(即方法结束)时,它们总是被销毁并收集垃圾,但这确实 not 意味着调用了Dispose()。将using 添加到局部变量声明中只是实现这一目标的一种方式。

    最后,这是,如果您的目标是 .NET Framework,那么您可能并没有真正使用 C# 8.0。

    你可能认为你是;我做到了。您可能正在运行 Visual Studio 2019 16.3+。您甚至可能安装了最新版本的 Microsoft.Net.Compilers 软件包,您正在获得 C# 8.0,对吗?但你不是。默认情况下,.NET Framework 的上限为 C# 7.3。

    在我的测试中,当我以 .NET 4.8 为目标时,Visual Studio 很智能,不会提供 C# 8.0 建议。但是,如果我以旧版本 (4.7.2) 为目标,我确实会收到此建议,然后会生成构建错误。 IDE 不会向您显示该错误 - 您的项目看起来很干净 - 但您在实际构建时会遇到两个语法错误。

    当面向 .NET 4.8 时,如果您尝试使用 C# 8.0 语法,您会得到友好的

    CS8370 C# 功能在 C# 7.3 中不可用。请使用 8.0 或更高版本的语言。

    并提议将<LangVersion>8.0</LangVersion> 添加到您的项目文件中(即使微软官方不支持)。它有效,但有警告。但对于较旧的 .NET 版本,情况似乎并非如此。因此,在旧项目中接受这些新语法提示时要格外小心!

    更新:关于触发提示的旧 NET Framework 版本我错了。罪魁祸首是Microsoft.Net.Compilers 的旧版本(2.10.0)。这是与旧版本 Visual Studio 兼容的最后一个版本。删除该包后,不再提供提示。

    【讨论】:

    • 是的,我也是这样:CS8370 C# Feature 在 C# 7.3 中不可用。请使用 8.0 或更高版本的语言...我不得不撤消接受的建议...因为我的 C#7.3!
    • 感谢Microsoft.Net.Compilers 的提示。 VS 不断建议重构会导致编译错误的事实让我发疯了。
    • 这让我很担心。让我想起 Jon Skeet 关于不带括号的 if 语句的故事 - stackoverflow.com/a/8020255/1904753
    • 同意,如果 using 块没有大括号会很奇怪。我并不是说我通常这样做,只是这两种语法(一种作为块声明,一种作为变量声明修饰符)非常相似,以至于我觉得很混乱。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-01
    • 2010-12-27
    相关资源
    最近更新 更多