【问题标题】:Is it possible to force an auto-property to use a readonly backing field?是否可以强制自动属性使用只读支持字段?
【发布时间】:2010-11-06 06:01:29
【问题描述】:

我的项目包含大量具有属性的类,其支持字段被标记为只读,因为它们仅在构造时设置。就风格而言,我喜欢使用自动属性,因为它消除了许多样板代码并鼓励使用属性成员而不是支持字段。但是,当使用自动属性时,我失去了支持字段的“只读性”。我知道当以这种方式标记字段时,编译器/运行时能够利用一些性能增强功能,因此我希望能够将我的自动属性标记为只读,如下所示:

[ReadOnly]
public string LastName { get; }

而不是

private readonly string _LastName;
public string LastName 
{ 
    get
    { 
        return _LastName;
    }
}

是否已经有一些机制可以做到这一点?如果不是,那么从只读的自定义支持字段中获得的性能提升真的值得吗?

将字段公开是另一种选择,我想,以这种方式公开字段似乎是错误的。即

public readonly string LastName;

【问题讨论】:

  • 我同意公开只读字段似乎是错误的。如果以后需要更改为属性,则更改会破坏兼容性。
  • 正如答案正确指出的那样,不,现在没有办法做到这一点。这是一个经常被请求的特性,并且在假设的未来语言版本的可能新特性列表中绝对是高位的。我个人希望拥有一整套相关的特性来鼓励以不可变的风格进行编程;这只是其中之一。

标签: c# .net


【解决方案1】:

恐怕不行,但你可以这样做:

public string LastName { get; private set; }

不如readonly,但也不算太差。

【讨论】:

  • readonly string Foo { get{ return "bar";} set;}string Foo { get{return "bar";}} 是否等效?
【解决方案2】:

不,很遗憾,没有办法做到这一点。就个人而言,我认为 C# 中自动实现的属性缺少两件事 - 默认值(我相信它将在 VB10 中)和只能在构造函数中设置的只读属性。换句话说,我希望能够做到:

public class Foo
{
    public string Tag { get; internal set; } = "Default value";

    // The "readonly" would imply "private" as it could only
    // be set from a constructor in the same class
    public int Value { get; readonly set; }

    public Foo()
    {
        // Valid to set property here, but nowhere else
        Value = 20;
    }
}

正如 Jared 所提到的,这意味着将对属性设置器的编译器调用更改为简单的字段赋值,并确保它们只发生在构造函数中。

这将使编写不可变类型更简单。不幸的是,这种情况在 C# 4 中不会改善。希望我们在 C# 5 中得到类似的东西......

【讨论】:

  • 同时,一个比另一个更受欢迎吗?似乎 setter-less 自动属性和只读支持字段实现都提供了不可变的实现。之后只是风格问题吗?
  • 我个人坚持只读支持字段,除非它是一次性代码。我喜欢知道它是正确地不可变的,即使我不小心尝试在我自己的类型中设置它。
  • 哎呀!二传手怎么可能是只读的?也许 public readonly int Value { get;放; }
【解决方案3】:

不,不是,如果是这样,如果没有重大调整,该功能将毫无用处。

只读字段只能通过构造函数进行验证设置。只能从生成的 setter 设置自动实现的属性。这些是不兼容的要求,将产生无法验证的代码。

是的,您可以使编译器足够聪明,以忽略设置器并直接进入构造函数中的支持字段。但是在 setter 本身中仍然是无法验证的。编译器需要从生成的代码中省略它,因为这将产生一个真正的只读属性。这会产生另一个矛盾,因为您仍然需要对该属性执行赋值语句。

Foo() {
  SomeProperty = "somevalue";
}

在这种情况下,代码看起来像是在调用属性的 setter。但实际上没有要调用的 setter,因为它必须从最终代码中省略。

编辑

这并不是说它不能完成。它可以,但需要 C# 的一些工作。

特别是他们必须提供一种方法来设置不能具有 setter 的属性的支持字段。有几种方法可以做到这一点。

  • 允许用户访问自动实现的属性的支持字段
  • 即使没有 setter,也允许使用 setter 样式语法,并让编译器将其转换为底层的字段访问
  • 发明一些新语法

我并不是说这些都是不错的选择,只是使此类功能发挥作用的可能性。

【讨论】:

  • 您需要一种替代语法,但我希望它可行。将添加一个答案...
  • @Jon 同意,我将答案改为“重大调整”
【解决方案4】:

从 C# 6.0 开始,答案是肯定的。您的示例可以编写如下,编译器会自动在属性后面生成一个只读字段。这称为 getter-only 自动属性。

public string LastName { get; }

来自https://msdn.microsoft.com/en-us/magazine/dn879355.aspx

getter-only 自动属性在结构和类中都可用 声明,但它们对结构特别重要,因为 结构不可变的最佳实践指南。而不是 需要六行左右来声明一个只读属性并初始化 它在 C# 6.0 之前,现在是单行声明和赋值 从构造函数内部就可以了。因此,声明 不可变结构现在不仅是正确的编程模式 对于结构,还有更简单的模式——一个非常受欢迎的变化 从以前的语法正确编码需要更多的努力。

【讨论】:

    【解决方案5】:

    我更喜欢真正的 readonly 支持字段,因为这样可以保证我不会在构建后更改该支持字段。

    【讨论】:

      【解决方案6】:

      没有,也没有。没有办法做到这一点,并且只读支持字段没有性能提升。

      【讨论】:

      猜你喜欢
      • 2012-02-07
      • 1970-01-01
      • 2017-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-03
      相关资源
      最近更新 更多