为什么code生成MSIL类称为<> c__DisplayClass1MSIL、code、LT、GT

由网友(轻狂人)分享简介:我有这个code,private bool MatchingBreak(IEnumerable breaks, int startMetres, int divisionPosition){CarriagewaySummary matchingBreak = breaks.Wh...

我有这个code,

private bool MatchingBreak(IEnumerable<CarriagewaySummary> breaks, int startMetres, int divisionPosition)
    {
        CarriagewaySummary matchingBreak = breaks.Where(x =>
        {
            return x.StartMetres == startMetres && x.EndMetres == divisionPosition;
        }).SingleOrDefault();
        return matchingBreak != null;
    }

为什么会产生的嵌套类称为LT;?> c__DisplayClass1在MSIL

Why does that generate a nested class called <>c__DisplayClass1 in the MSIL?

.class nested private auto ansi sealed beforefieldinit <>c__DisplayClass1
extends object
{
.custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
    01 00 00 00
)
// Fields
.field public int32 startMetres
.field public int32 divisionPosition

// Methods
.method public hidebysig specialname rtspecialname 
    instance void .ctor () cil managed 
{
    // Method begins at RVA 0x56fb
    // Code size 7 (0x7)
    .maxstack 8

    IL_0000: ldarg.0
    IL_0001: call instance void object::.ctor()
    IL_0006: ret
} // End of method <>c__DisplayClass1..ctor

.method public hidebysig 
    instance bool <MatchingBreak>b__0 (
        class TreatmentLengthDynamicSegmentation.Domain.CarriagewaySummary x
    ) cil managed 
{
    // Method begins at RVA 0x5704
    // Code size 37 (0x25)
    .maxstack 2
    .locals init (
        [0] bool 
    )

    IL_0000: nop
    IL_0001: ldarg.1
    IL_0002: callvirt instance int32 TreatmentLengthDynamicSegmentation.Domain.CarriagewaySummary::get_StartMetres()
    IL_0007: ldarg.0
    IL_0008: ldfld int32 class TreatmentLengthDynamicSegmentation.ScriptHelpers.DivisionManager/<>c__DisplayClass1::startMetres
    IL_000d: bne.un.s IL_001f
    IL_000f: ldarg.1
    IL_0010: callvirt instance int32 TreatmentLengthDynamicSegmentation.Domain.CarriagewaySummary::get_EndMetres()
    IL_0015: ldarg.0
    IL_0016: ldfld int32 class TreatmentLengthDynamicSegmentation.ScriptHelpers.DivisionManager/<>c__DisplayClass1::divisionPosition
    IL_001b: ceq
    IL_001d: br.s IL_0020
    IL_001f: ldc.i4.0
    IL_0020: stloc.0
    IL_0021: br.s IL_0023
    IL_0023: ldloc.0
    IL_0024: ret
} // End of method <>c__DisplayClass1.<MatchingBreak>b__0

} // End of class TreatmentLengthDynamicSegmentation.ScriptHelpers.DivisionManager/<>c__DisplayClass1

生成的code干扰了Nitriq code分析,所以我想知道为什么它的存在。

The generated code is interfering with Nitriq Code Analysis, so I want to understand why it's there.

推荐答案

如果你在一个lambda使用局部变量它需要在堆上。拉姆达可能会创建它退出功能后才能使用。普通局部变量(生活在堆栈/寄存器的)无效时,函数退出,所以他们不能在这里使用。

If you use local variables in a lambda it needs to be on the heap. The lambda might be used after the function which created it exits. Normal local variables (living on the stack/registers) become invalid when the function exits, so they can't be used here.

因此​​,C#编译器创建一个类来保存捕获的局部变量。这就是你看到的那个。

So the C# compiler creates a class to hold captured local variables. That's the one you're seeing.

请注意该C#捕获实际的变量,而不是它的当前值。因此,在概念上它捕获的参考。捕获的语义意味着编译器需要创建每个范围一个容器对象。

Note that C# captures the actual variable, not its current value. So conceptually it's captured by reference. The semantics of capturing mean that the compiler needs to create one container object per scope.

http://csharpindepth.com/Articles/Chapter5/Closures.aspx

在你的code

x =>
    {
        return x.StartMetres == startMetres && x.EndMetres == divisionPosition;
    }

在拉姆达使用 startMetres divisionPosition ,所以他们都得到抓获并提出在该嵌套类。

The lambda uses startMetres and divisionPosition, so both of them get captured and are put in that nested class.

阅读全文

相关推荐

最新文章