Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have this 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;
    }

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

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
384 views
Welcome To Ask or Share your Answers For Others

1 Answer

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.

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

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


In your code

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

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


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...