在属性签名中,C#中的赋值是什么?

我遇到了一些代码说

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

现在我对Lambda表达式有一定的了解。 我只是没有看到它以这种方式使用它。

上述声明和声明之间的区别是什么?

public int MaxHealth  = x ? y:z;

你看到的是一个表达式的成员,而不是一个lambda表达式。

当编译器遇到一个表达式属性成员时,它将基本上将它转换为get ter,如下所示:

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

(您可以通过将代码泵入名为TryRoslyn的工具来验证这一点。)

与大多数C#6功能一样,表达式成员 - 仅仅是语法糖。 这意味着它们不提供通过现有功能无法实现的功能。 相反,这些新功能允许使用更具表达力和简洁的语法

正如您所看到的,表达式成员具有一些捷径,可以使属性成员更紧凑:

  • 没有必要使用return语句,因为编译器可以推断出你想返回表达式的结果
  • 不需要创建语句块,因为它只有一个表达式
  • 不需要使用get关键字,因为它使用表达式 - 体式成员语法。
  • 我最后一点是大胆的,因为它与您的实际问题有关,我现在将回答。

    和...之间的不同...

    // expression-bodied member property
    public int MaxHealth => x ? y:z;
    

    和...

    // field with field initializer
    public int MaxHealth = x ? y:z;
    

    是相同的区别... ... -

    public int MaxHealth
    {
        get
        {
            return x ? y:z;
        }
    }
    

    和...

    public int MaxHealth = x ? y:z;
    

    其中 - 如果你理解属性 - 应该是显而易见的。

    但要清楚的是:第一个列表是一个吸气罩下的属性,每次访问时都会调用它。 第二个列表是具有字段初始值设定项的字段,当该类型被实例化时,其表达式仅被计算一次。

    语法上的这种差异实际上是相当微妙的,并且可能导致Bill Wagner在题为“AC#6 gotcha:初始化与表达体式成员”的帖子中描述的“陷阱”。

    尽管表达式成员是lambda表达式,但它们不是lambda表达式。 根本区别在于lambda表达式导致委托实例或表达式树。 表达式成员只是编译器在幕后生成属性的指令。 相似性(或多或少)以箭头开始和结束( => )。

    我还要补充一点,表达式成员不限于财产成员。 他们在所有这些成员上工作:

  • 属性
  • 索引
  • 方法
  • 运营商
  • 但是,他们不适用于这些成员:

  • 构造函数
  • Deconstructors
  • 嵌套类型
  • 活动
  • 字段

  • 这是C#6的一个新特性,称为表达式主体成员,它允许您使用类似lambda函数的函数定义仅限getter属性。

    虽然它被认为是以下语法糖,但它们可能不会产生相同的IL:

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

    事实证明,如果你编译上述两个版本并比较每个版本生成的IL,你会发现它们几乎是相同的。

    在名为TestClass的类中定义时,以下是此答案中经典版本的IL:

    .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<int64, class MemoryAddress> TestClass::Memory
        IL_0007: ldarg.0
        IL_0008: ldfld int64 TestClass::Address
        IL_000d: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::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<int64, class MemoryAddress> TestClass::Memory
        IL_0022: ldarg.0
        IL_0023: ldfld int64 TestClass::Address
        IL_0028: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::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<int32>(int64)
    
        IL_0042: stloc.0
        IL_0043: br.s IL_0045
    
        IL_0045: ldloc.0
        IL_0046: ret
    } // end of method TestClass::get_MaxHealth
    

    以下是在名为TestClass的类中定义的表达式成员版本的IL:

    .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<int64, class MemoryAddress> TestClass::Memory
        IL_0006: ldarg.0
        IL_0007: ldfld int64 TestClass::Address
        IL_000c: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::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<int64, class MemoryAddress> TestClass::Memory
        IL_0021: ldarg.0
        IL_0022: ldfld int64 TestClass::Address
        IL_0027: callvirt instance !1 class [mscorlib]System.Collections.Generic.Dictionary`2<int64, class MemoryAddress>::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<int32>(int64)
    
        IL_0041: ret
    } // end of method TestClass::get_MaxHealth
    

    请参阅https://msdn.microsoft.com/en-us/magazine/dn802602.aspx以获取有关C#6中此功能和其他新功能的更多信息。

    看到这篇文章C#3.0+中的属性和字段之间的区别字段和C#中的属性获得者之间的区别。


    好的...我发表了一个评论,他们有所不同,但无法解释如何,但现在我知道了。

    String Property { get; } = "value";
    

    是不一样的

    Property => value
    

    这是区别...

    当您使用自动初始值设定项时,该属性会创建值的实例并持续使用该值。 在上面的文章中,有一条与比尔瓦格纳断开的链接,这很好地解释了这一点,我搜索了正确的链接以便自己理解它。

    在我的情况下,我让我的属性自动初始化视图的ViewModel中的命令。 我改变了属性使用表达式初始化器和命令CanExecute停止工作。

    这是它看起来像什么,这是发生了什么。

    Command MyCommand { get; } = new Command();  //works
    

    这是我改变它的。

    Command MyCommand => new Command();  //doesn't work properly
    

    这里的区别是当我使用{ get; } = { get; } =我在该属性中创建并引用了SAME命令。 当我使用=>我实际上创建一个新的命令并在每次调用属性时返回它。 因此,我永远无法更新我的命令上的CanExecute ,因为我总是告诉它更新该命令的新参考。

    { get; } = // same reference
    =>         // new reference
    

    所有这一切说,如果你只是指向一个支持领域,那么它工作正常。 这只有在auto或expression body创建返回值时才会发生。

    链接地址: http://www.djcxy.com/p/75171.html

    上一篇: What is the => assignment in C# in a property signature

    下一篇: Can I initialize public properties of a class using a different type in C#?