代码之家  ›  专栏  ›  技术社区  ›  Mikkel R. Lund

简单类型的只读自动属性:Initializer VS Expression Body Getter

  •  8
  • Mikkel R. Lund  · 技术社区  · 8 年前

    在C#6.0中,新语法允许我们使用初始值设定项编写只读自动属性:

    public bool AllowsDuplicates { get; } = true;
    

    同样,我们可以使用表达式体getter编写它:

    public bool AllowsDuplicates => true;
    

    对于简单类型,这两种类型应该具有相同的效果:返回true的只读auto属性。

    但他们中的一个比另一个更受欢迎吗?我怀疑前者使用了支持字段:

    private readonly bool _backingField = true;
    public bool AllowsDuplicates {
        get {
            return _backingField;
        }
    }
    

    而后者则变成了类似这样的东西:

    public bool AllowsDuplicates {
        get {
            return true;
        }
    }
    

    是这样吗,还是编译器比这更聪明?

    2 回复  |  直到 8 年前
        1
  •  8
  •   Will Ray    8 年前

    我怀疑前者使用了后场

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

    但他们中的一个比另一个更受欢迎吗?

    对于 问题中的具体示例 ,auto属性将允许构造函数请求 bool 并分配它。第二种风格不会。如果目的是将其用作“默认值”,可以在构造期间修改一次,则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;
    

    构造函数中分配了一个值,其余的是基于它计算的属性值。

        2
  •  3
  •   Arturo Menchaca    8 年前

    我怀疑前者使用了支持字段,而后者是 变成了这样的,对吗?

    是的,就像你说的, 自动属性初始化程序 在声明时设置支持字段的值。

    以及 Expression酒体 是对 get 身体

    但他们中的一个比另一个更受欢迎吗?

    取决于,如果您的属性更复杂,只返回相同的值,例如 Elapsed Current 属性,或需要计算的任何内容 Expression酒体 更合适。
    在一个 Expression酒体 定义每次访问属性时要执行的代码。

    如果属性被认为是不可变的,那么只需要一个初始常量值 自动属性初始化程序 将是首选。