为什么闭包对于使用声明的 C# 8.0 中的变量不同?
Why are closures different for variables from C# 8.0 using declarations?
我注意到 C# 8.0 编译器为捕获的 IDisposable
变量构建闭包 classes 的方式有所不同,这些变量是使用 C# 8.0 using 声明声明的,而不是使用声明的变量classic using 语句。
考虑这个简单的问题 class:
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 语句声明这两个变量,则闭包 class 的生成方式会大不相同。这是示例代码:
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 语句完全相同,后者被视为块它在其中声明的当前块。
更不用说为使用声明生成闭包 class 的方式看起来更清晰,最重要的是,更 通过反射更容易探索。
如果有人知道为什么会发生这种情况,我希望得到一些见解。
谢谢!
编译器正在为每个 "scope"...生成一个 [CompilerGenerated]
class
... 在第一个示例中,只有一个作用域,即整个 Test()
方法。在第二个例子中(你没有给出),有两个范围,两个 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# 8.0 编译器为捕获的 IDisposable
变量构建闭包 classes 的方式有所不同,这些变量是使用 C# 8.0 using 声明声明的,而不是使用声明的变量classic using 语句。
考虑这个简单的问题 class:
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 语句声明这两个变量,则闭包 class 的生成方式会大不相同。这是示例代码:
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 语句完全相同,后者被视为块它在其中声明的当前块。
更不用说为使用声明生成闭包 class 的方式看起来更清晰,最重要的是,更 通过反射更容易探索。
如果有人知道为什么会发生这种情况,我希望得到一些见解。
谢谢!
编译器正在为每个 "scope"...生成一个 [CompilerGenerated]
class
... 在第一个示例中,只有一个作用域,即整个 Test()
方法。在第二个例子中(你没有给出),有两个范围,两个 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}");