![](/img/trans.png)
[英]What causes excessive anonymous method closures (c__DisplayClass1) in C#?
[英]Why Does Code Generate MSIL Class Called <>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代碼分析,所以我想了解它為什么存在。
如果在lambda中使用局部變量,則需要在堆上。 lambda可能在創建它的函數退出后使用。 當函數退出時,正常的局部變量(存在於堆棧/寄存器中)變為無效,因此不能在此處使用它們。
因此C#編譯器創建一個類來保存捕獲的局部變量。 這就是你所看到的那個。
請注意,C#捕獲實際變量,而不是其當前值。 所以在概念上它是通過引用捕獲的。 捕獲的語義意味着編譯器需要為每個作用域創建一個容器對象。
http://csharpindepth.com/Articles/Chapter5/Closures.aspx
在你的代碼中
x =>
{
return x.StartMetres == startMetres && x.EndMetres == divisionPosition;
}
lambda使用startMetres
和divisionPosition
,因此它們都被捕獲並放入該嵌套類中。
你正在使用lambda作為Where擴展方法,這需要編譯器在lambda捕獲外部變量時生成一個類。 在這種情況下,捕獲startMetres
和divisionPosition
參數。
您將看到編譯器生成的類以保存捕獲的變量。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.