c# - 为什么闭包对于使用声明的 C# 8.0 中的变量不同?

标签 c# .net visual-studio .net-core roslyn

我注意到 C# 8.0 编译器为捕获的 IDisposable 变量构建闭包类的方式有所不同,这些变量是使用 C# 8.0 using 声明声明的,与使用经典 using 语句声明的变量相反.

考虑这个简单的类:

public class DisposableClass : IDisposable
{
    public void Dispose() { }
}

还有这个示例代码:

public void Test()
{
    using var disposable1 = new DisposableClass();
    using var disposable2 = new DisposableClass();

    Action action = () => Console.Write($"{disposable1}{disposable2}");
}

编译器生成这段代码:

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public DisposableClass disposable1;

    public DisposableClass disposable2;

    internal void <Test>b__0()
    {
        Console.Write(string.Format("{0}{1}", disposable1, disposable2));
    }
}

public void Test()
{
    <>c__DisplayClass0_0 <>c__DisplayClass0_ = new <>c__DisplayClass0_0();
    <>c__DisplayClass0_.disposable1 = new DisposableClass();
    try
    {
        <>c__DisplayClass0_.disposable2 = new DisposableClass();
        try
        {
            Action action = new Action(<>c__DisplayClass0_.<Test>b__0);
        }
        finally
        {
            if (<>c__DisplayClass0_.disposable2 != null)
            {
                ((IDisposable)<>c__DisplayClass0_.disposable2).Dispose();
            }
        }
    }
    finally
    {
        if (<>c__DisplayClass0_.disposable1 != null)
        {
            ((IDisposable)<>c__DisplayClass0_.disposable1).Dispose();
        }
    }
}

这看起来完全没问题。但后来我注意到,如果我用 using 语句声明这两个变量,则生成的闭包类会大不相同。这是示例代码:

public void Test()
{
    using (var disposable1 = new DisposableClass())
    using (var disposable2 = new DisposableClass())
    {
        Action action = () => Console.Write($"{disposable1}{disposable2}");
    }
}

这就是我得到的:

[CompilerGenerated]
private sealed class <>c__DisplayClass0_0
{
    public DisposableClass disposable1;
}

[CompilerGenerated]
private sealed class <>c__DisplayClass0_1
{
    public DisposableClass disposable2;

    public <>c__DisplayClass0_0 CS$<>8__locals1;

    internal void <Test>b__0()
    {
        Console.Write(string.Format("{0}{1}", CS$<>8__locals1.disposable1, disposable2));
    }
}

为什么会这样?其余代码看起来完全相同,而且我认为 using 声明应该与 using 声明完全相同,后者被视为阻止它在其中声明的当前 block 。

更不用说为使用声明生成闭包类的方式看起来更清晰,最重要的是,通过反射更容易探索。

如果有人知道为什么会这样,我希望得到一些见解。

谢谢!

最佳答案

编译器正在为每个“作用域”生成一个[CompilerGenerated] class...在第一个例子中,有一个作用域,整个测试() 方法。在第二个示例中(您没有给出),有两个范围,两个 using

第二个例子的代码大概是:

public void Test()
{
    using (var disposable1 = new DisposableClass())
    {
        using (var disposable2 = new DisposableClass())
        {
            Action action = () => Console.Write($"{disposable1}{disposable2}");
        }
    }
}

正如 juharr 所指出的,这两个代码块产生相同的代码:

using (DisposableClass disposable1 = new DisposableClass(), disposable2 = new DisposableClass())
{
    Action action = () => Console.Write($"{disposable1}{disposable2}");
}

using var disposable1 = new DisposableClass();
using var disposable2 = new DisposableClass();

Action action = () => Console.Write($"{disposable1}{disposable2}");

关于c# - 为什么闭包对于使用声明的 C# 8.0 中的变量不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57593184/

相关文章:

c# - 第二次调用同一个 DbContext 导致错误 'DbContext has been disposed'

c# - KryptonSeparator 调整大小问题

c# - 为什么不 checkin AssemblyInfo.cs

c# - 如何将运行时计算的非持久只读属性正确添加到 Linq To SQL 数据类

C# System.TypeLoadException : Could not load type because it contains an object field at offset - code from . .net 核心上的 net 框架

.net - Win32_NetworkAdapterConfiguration.EnableStatic()可以用于设置多个IP地址吗?

visual-studio - 在Visual Studio 2010的预生成步骤中吞下错误

c# - Jenkins 未能建立C#项目

c# - 如何在 webapi 构造函数中获取主要用户?

c# - 主构造函数不再在 VS2015 中编译