2011-05-16 55 views
7

我有這樣的代碼,爲什麼代碼生成MSIL類名爲<> c__DisplayClass1

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; 
    } 

爲什麼產生在MSIL稱爲<嵌套類> c__DisplayClass1?

.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 

生成的代碼干擾Nitriq代碼分析,所以我想明白爲什麼它存在。

+0

我想知道,你爲什麼選擇使用塊lambda語法?爲什麼不'breaks.Where(x => x.StartMetres == startMetres && x.EndMetres == divisionPosition).SingleOrDefault();'? – Dykam 2011-05-16 08:59:53

回答

9

如果你在lambda中使用局部變量,它需要在堆上。 lambda可能在創建它的函數退出後使用。當函數退出時,正常的局部變量(位於堆棧/寄存器上)變爲無效,因此它們不能在此處使用。

所以C#編譯器創建一個類來保存捕獲的本地變量。那是你看到的那個。

請注意,C#捕獲實際變量,而不是其當前值。所以從概念上講,它是通過參考獲取的。捕獲的語義意味着編譯器需要爲每個作用域創建一個容器對象。

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


在你的代碼

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

拉姆達使用startMetresdivisionPosition,所以他們都得到捕獲,並把該嵌套類。

6

您正在使用Where擴展方法的lambda表達式,這需要編譯器在lambda捕獲外部變量時生成類。在這種情況下,捕獲參數startMetresdivisionPosition

你正在看到編譯器生成的類來保存捕獲的變量。

+0

那麼對於任何擴展方法,它是這樣做的嗎?爲什麼要這樣做? – peter 2011-05-16 04:15:47

+1

這不是擴展方法,它是lambda。它需要一個類來實際保存你通過的匿名方法。 – dlev 2011-05-16 04:17:15

+0

有道理。謝謝。 – peter 2011-05-16 04:18:06

相關問題