简单类型的只读 Auto-属性:初始化器 VS 表达式主体 Getter
Read-Only Auto-Property for Simple Types: Initializer VS Expression Body Getter
在 C# 6.0 中,新语法允许我们使用初始化程序编写只读自动属性:
public bool AllowsDuplicates { get; } = true;
同样,我们可以用表达式体来写getter:
public bool AllowsDuplicates => true;
对于简单类型,这两个应该具有相同的效果:一个只读的 auto-属性,returns true。
但是其中一个比另一个更受欢迎吗?我怀疑前者使用了支持字段:
private readonly bool _backingField = true;
public bool AllowsDuplicates {
get {
return _backingField;
}
}
而后者变成了这样的东西:
public bool AllowsDuplicates {
get {
return true;
}
}
是这样吗,还是编译器比这更聪明?
I suspect that the former uses a backing field
auto-属性 初始化程序实际上创建了一个支持字段!您可以将其放入 ILSpy 并在输出中查看:
public class One
{
public bool AllowsDuplicates
{
[CompilerGenerated]
get
{
return this.<AllowsDuplicates>k__BackingField;
}
}
public One()
{
this.<AllowsDuplicates>k__BackingField = true;
base..ctor();
}
}
public class Two
{
public bool AllowsDuplicates
{
get
{
return true;
}
}
}
But is one of them preferred over the other?
对于问题中的具体示例,自动属性将允许构造函数请求bool
并分配它。第二种风格不会。如果打算将其用作可以在构造期间修改一次的 "default value",那么 auto-属性 是正确的选择。
class Test
{
// Could assign this in the second constructor
public bool AllowsDuplicates { get; } = true;
// Cannot assign this in the second constructor
public bool AllowsDuplicates => true;
public Test()
{
// Default value used
}
public Test(bool value)
{
AllowsDuplicates = value;
}
}
我看到表达式主体语法在它作为用作 属性 的小函数的掩护时最胜出。 Eric Lippert's dedoublifier 中的结构有一个很好的例子:
public DoubleHelper(double d)
{
this.RawBits = (ulong)BitConverter.DoubleToInt64Bits(d);
}
public ulong RawBits { get; }
// RawSign is 1 if zero or negative, 0 if zero or positive
public int RawSign => (int)(RawBits >> 63);
public int RawExponent => (int)(RawBits >> 52) & 0x7FF;
public long RawMantissa => (long)(RawBits & 0x000FFFFFFFFFFFFF);
public bool IsNaN => RawExponent == 0x7ff && RawMantissa != 0;
public bool IsInfinity => RawExponent == 0x7ff && RawMantissa == 0;
public bool IsZero => RawExponent == 0 && RawMantissa == 0;
public bool IsDenormal => RawExponent == 0 && RawMantissa != 0;
在构造函数中分配了一个值,其余 属性 个值是根据它计算的。
I suspect that the former uses a backing field, whereas the latter is
turned into something like, Is that right?
是的,就像你说的,Auto-属性 Initializer 在声明的那一刻设置了支持字段的值。
而 Expression-bodied 是 get
主体的语法简化。
But is one of them preferred over the other?
取决于,如果您的 属性 比仅返回相同的值更复杂,例如 Elapsed
或 Current
属性,或任何需要的东西要计算 Expression-bodied 更合适。
在 Expression-bodied 中,您定义每次访问 属性 时要执行的代码。
如果您的 属性 应该是不可变的,只是一个初始常量值,那么 Auto-属性 Initializer 将是首选。
在 C# 6.0 中,新语法允许我们使用初始化程序编写只读自动属性:
public bool AllowsDuplicates { get; } = true;
同样,我们可以用表达式体来写getter:
public bool AllowsDuplicates => true;
对于简单类型,这两个应该具有相同的效果:一个只读的 auto-属性,returns true。
但是其中一个比另一个更受欢迎吗?我怀疑前者使用了支持字段:
private readonly bool _backingField = true;
public bool AllowsDuplicates {
get {
return _backingField;
}
}
而后者变成了这样的东西:
public bool AllowsDuplicates {
get {
return true;
}
}
是这样吗,还是编译器比这更聪明?
I suspect that the former uses a backing field
auto-属性 初始化程序实际上创建了一个支持字段!您可以将其放入 ILSpy 并在输出中查看:
public class One
{
public bool AllowsDuplicates
{
[CompilerGenerated]
get
{
return this.<AllowsDuplicates>k__BackingField;
}
}
public One()
{
this.<AllowsDuplicates>k__BackingField = true;
base..ctor();
}
}
public class Two
{
public bool AllowsDuplicates
{
get
{
return true;
}
}
}
But is one of them preferred over the other?
对于问题中的具体示例,自动属性将允许构造函数请求bool
并分配它。第二种风格不会。如果打算将其用作可以在构造期间修改一次的 "default value",那么 auto-属性 是正确的选择。
class Test
{
// Could assign this in the second constructor
public bool AllowsDuplicates { get; } = true;
// Cannot assign this in the second constructor
public bool AllowsDuplicates => true;
public Test()
{
// Default value used
}
public Test(bool value)
{
AllowsDuplicates = value;
}
}
我看到表达式主体语法在它作为用作 属性 的小函数的掩护时最胜出。 Eric Lippert's dedoublifier 中的结构有一个很好的例子:
public DoubleHelper(double d)
{
this.RawBits = (ulong)BitConverter.DoubleToInt64Bits(d);
}
public ulong RawBits { get; }
// RawSign is 1 if zero or negative, 0 if zero or positive
public int RawSign => (int)(RawBits >> 63);
public int RawExponent => (int)(RawBits >> 52) & 0x7FF;
public long RawMantissa => (long)(RawBits & 0x000FFFFFFFFFFFFF);
public bool IsNaN => RawExponent == 0x7ff && RawMantissa != 0;
public bool IsInfinity => RawExponent == 0x7ff && RawMantissa == 0;
public bool IsZero => RawExponent == 0 && RawMantissa == 0;
public bool IsDenormal => RawExponent == 0 && RawMantissa != 0;
在构造函数中分配了一个值,其余 属性 个值是根据它计算的。
I suspect that the former uses a backing field, whereas the latter is turned into something like, Is that right?
是的,就像你说的,Auto-属性 Initializer 在声明的那一刻设置了支持字段的值。
而 Expression-bodied 是 get
主体的语法简化。
But is one of them preferred over the other?
取决于,如果您的 属性 比仅返回相同的值更复杂,例如 Elapsed
或 Current
属性,或任何需要的东西要计算 Expression-bodied 更合适。
在 Expression-bodied 中,您定义每次访问 属性 时要执行的代码。
如果您的 属性 应该是不可变的,只是一个初始常量值,那么 Auto-属性 Initializer 将是首选。