What is the => assignment in C# in a property signature

前端 未结 7 1106
执念已碎
执念已碎 2020-11-22 00:29

I came across some code that said

public int MaxHealth => 
         Memory[Address].IsValid ? 
         Memory[Address].Read(Offs.Life.MaxHp)          


        
7条回答
  •  抹茶落季
    2020-11-22 01:25

    This is a new feature of C# 6 called an expression bodied member that allows you to define a getter only property using a lambda like function.

    While it is considered syntactic sugar for the following, they may not produce identical IL:

    public int MaxHealth
    {
        get
        {
            return Memory[Address].IsValid
                   ?   Memory[Address].Read(Offs.Life.MaxHp)
                   :   0;
        }
    }
    

    It turns out that if you compile both versions of the above and compare the IL generated for each you'll see that they are NEARLY the same.

    Here is the IL for the classic version in this answer when defined in a class named TestClass:

    .property instance int32 MaxHealth()
    {
        .get instance int32 TestClass::get_MaxHealth()
    }
    
    .method public hidebysig specialname 
        instance int32 get_MaxHealth () cil managed 
    {
        // Method begins at RVA 0x2458
        // Code size 71 (0x47)
        .maxstack 2
        .locals init (
            [0] int32
        )
    
        IL_0000: nop
        IL_0001: ldarg.0
        IL_0002: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2 TestClass::Memory
        IL_0007: ldarg.0
        IL_0008: ldfld int64 TestClass::Address
        IL_000d: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2::get_Item(!0)
        IL_0012: ldfld bool MemoryAddress::IsValid
        IL_0017: brtrue.s IL_001c
    
        IL_0019: ldc.i4.0
        IL_001a: br.s IL_0042
    
        IL_001c: ldarg.0
        IL_001d: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2 TestClass::Memory
        IL_0022: ldarg.0
        IL_0023: ldfld int64 TestClass::Address
        IL_0028: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2::get_Item(!0)
        IL_002d: ldarg.0
        IL_002e: ldfld class Offs TestClass::Offs
        IL_0033: ldfld class Life Offs::Life
        IL_0038: ldfld int64 Life::MaxHp
        IL_003d: callvirt instance !!0 MemoryAddress::Read(int64)
    
        IL_0042: stloc.0
        IL_0043: br.s IL_0045
    
        IL_0045: ldloc.0
        IL_0046: ret
    } // end of method TestClass::get_MaxHealth
    

    And here is the IL for the expression bodied member version when defined in a class named TestClass:

    .property instance int32 MaxHealth()
    {
        .get instance int32 TestClass::get_MaxHealth()
    }
    
    .method public hidebysig specialname 
        instance int32 get_MaxHealth () cil managed 
    {
        // Method begins at RVA 0x2458
        // Code size 66 (0x42)
        .maxstack 2
    
        IL_0000: ldarg.0
        IL_0001: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2 TestClass::Memory
        IL_0006: ldarg.0
        IL_0007: ldfld int64 TestClass::Address
        IL_000c: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2::get_Item(!0)
        IL_0011: ldfld bool MemoryAddress::IsValid
        IL_0016: brtrue.s IL_001b
    
        IL_0018: ldc.i4.0
        IL_0019: br.s IL_0041
    
        IL_001b: ldarg.0
        IL_001c: ldfld class [mscorlib]System.Collections.Generic.Dictionary`2 TestClass::Memory
        IL_0021: ldarg.0
        IL_0022: ldfld int64 TestClass::Address
        IL_0027: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2::get_Item(!0)
        IL_002c: ldarg.0
        IL_002d: ldfld class Offs TestClass::Offs
        IL_0032: ldfld class Life Offs::Life
        IL_0037: ldfld int64 Life::MaxHp
        IL_003c: callvirt instance !!0 MemoryAddress::Read(int64)
    
        IL_0041: ret
    } // end of method TestClass::get_MaxHealth
    

    See https://msdn.microsoft.com/en-us/magazine/dn802602.aspx for more information on this and other new features in C# 6.

    See this post Difference between Property and Field in C# 3.0+ on the difference between a field and a property getter in C#.

    Update:

    Note that expression-bodied members were expanded to include properties, constructors, finalizers and indexers in C# 7.0.

提交回复
热议问题