为什么使用声明从C#8.0到变量的闭包不同?

Ser*_*694 8 .net c# visual-studio roslyn .net-core

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

考虑这个简单的类:

public class DisposableClass : IDisposable
{
    public void Dispose() { }
}
Run Code Online (Sandbox Code Playgroud)

和此示例代码:

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

    Action action = () => Console.Write($"{disposable1}{disposable2}");
}
Run Code Online (Sandbox Code Playgroud)

编译器生成以下代码:

[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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

这就是我得到的:

[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));
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么会这样?其余代码看起来相同,我认为using声明应该与using语句完全相同, using语句被视为阻塞了在其中声明的当前块。

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

如果有人知道为什么会这样,我很乐意提供一些见识。

谢谢!

xan*_*tos 5

编译器[CompilerGenerated] class为每个“作用域” 生成一个...在第一个示例中,只有一个作用域,即整个Test()方法。在第二个示例(您不提供)中,有两个范围,两个using

第二个示例的代码可能是:

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

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

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

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

Action action = () => Console.Write($"{disposable1}{disposable2}");
Run Code Online (Sandbox Code Playgroud)