C#中的属性签名是什么?

我遇到了一些代码说

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

现在我对Lambdaexpression式有些熟悉了。 我只是没有看到它用这种方式。

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

 public int MaxHealth = x ? y:z; 

你正在看的是一个expression式的成员 ,而不是一个lambdaexpression式。

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

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

(您可以通过将代码抽取到名为TryRoslyn的工具来validation这一点 。)

与大多数C#6特性一样,expression式成员只是 语法上的糖 。 这意味着它们不提供通过现有function无法实现的function。 相反,这些新function允许使用更具expression性和简洁性的语法

正如你所看到的,expression式的成员有一些捷径可以使财产成员更加紧凑:

  • 没有必要使用return语句,因为编译器可以推断出你想返回expression式的结果
  • 没有必要创build一个语句块,因为它只是一个expression式
  • 没有必要使用get关键字,因为它使用expression式 – 体式成员语法。

我最后一点是大胆的,因为这与你的实际问题有关,我现在要回答。

和…之间的不同…

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

哪一个 – 如果你理解属性 – 应该是显而易见的。

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

语法上的差异实际上是相当微妙的,并且可能导致比尔·瓦格纳在“AC#6窍门:初始化与expression身体成员”一文中描述的“陷阱”

尽pipeexpression式成员是lambdaexpression式,但它们不是 lambdaexpression式。 最根本的区别是lambdaexpression式导致委托实例或expression式树。 expression式成员只是编译器在后台生成属性的一个指令。 相似性(或多或less)以箭头开始和结束( => )。

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

  • 属性
  • 索引
  • 方法
  • 运营商

但是,他们不在这些成员上工作:

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

这是C#6的一个新特性,称为expression式主体成员,允许您使用类似lambda函数来定义仅获取特定属性。

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

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

事实certificate,如果您编译上述两个版本并比较每个版本生成的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的类中定义的expression式成员版本的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中此function和其他新function的更多信息。;

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

它被称为Expression Bodied Member ,它是在C#6中引入的。它仅仅是一个get唯一属性的语法糖。

这相当于:

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

相当于一个方法声明是可用的:

 public string HelloWorld() => "Hello World"; 

主要让你缩短样板。

好吧…我发表了一个评论,他们是不同的,但不能解释究竟如何,但现在我知道。

 String Property { get; } = "value"; 

是不一样的

 Property => value 

这是区别…

当您使用自动初始值设定项时,该属性将创build值的实例并持续使用该值。 在上面的post中,有一个与比尔·瓦格纳的链接断了,解释了这一点,我search了正确的链接,自己理解它。

在我的情况,我有我的财产自动初始化一个视图ViewModel命令。 我改变了属性使用expression式初始化和命令CanExecute停止工作。

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

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

这是我改变它。

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

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

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

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

其他重要的一点是'=>'可以用来代替'get', 用于'只有'方法 – 它不能和'set'一起使用。