为什么属性不能只读?

时间:2010-01-30 03:48:47

标签: c# properties

this answer的评论中提出了这个问题。建议不能使用只读属性作为使用字段而不是属性的潜在原因。

例如:

class Rectangle
{
   private readonly int _width;
   private readonly int _height;

   public Rectangle(int width, int height)
   {
      _width = width;
      _height = height;
   }

   public int Width { get { return _width; } }
   public int Height { get { return _height; } }
}

但你为什么不能这样做呢?

public int Width { get; readonly set; }

编辑(澄清):您可以在第一个示例中实现此功能。但是为什么你不能用自动实现的属性速记来做同样的事情呢?它也不会那么混乱,因为你不必直接访问构造函数中的字段;所有访问都将通过该属性。

编辑(更新):从C#6.0开始,支持只读属性! object MyProp { get; }此属性可以设置为内联(object MyProp { get; } = ...)或构造函数,但不在其他地方(就像readonly字段一样)。

7 个答案:

答案 0 :(得分:23)

因为语言不允许。

这看起来似乎是一个无聊的答案:毕竟,语言设计师可以声明如果你在自动属性上使用readonly那么它就意味着“该属性是可设置的但是仅在构造函数“。

但功能不是免费的。 (Eric Gunnerson将其表示为“每个功能都以minus 100 points开头。”)要实现只读自动属性,需要额外的编译器工作来支持属性上的readonly修饰符(它目前仅适用于字段),生成适当的后备字段并将属性的sets转换为支持字段的赋值。通过声明一个只读后备字段并编写一行属性getter来支持用户可以合理轻松完成的工作,这是一项相当多的工作,而且这项工作在实现其他功能方面会产生成本。

所以,非常认真地说,答案是语言设计者和实施者要么从未想过这个想法,要么 - 更有可能 - 他们认为这样做会很好,但是决定有更好的地方去度过他们的想法。有限的资源。没有技术限制阻止语言设计者和实现者提供您建议的功能:原因更多的是软件开发的经济性。

答案 1 :(得分:16)

如果您希望在功能方面将属性设置为“只读”,则只需按照帖子中的说明提供get方法即可。

public int Width { get { return _width; } } 
public int Height { get { return _height; } } 

如果您尝试写入它们,编译器甚至会将它们称为“只读”。

对于一个属性,附加的readonly项将与提供set方法发生冲突。它似乎对我来说语法不好,即阅读它的人(或编译器,如何)知道什么是优先的:readonlyset

此外,正如您引用的答案中所解释的那样,readonly仅适用于字段和限制写入这些字段到类的实例化。对于属性,即使在构造函数中,如果它们只有get方法,也不能写入它们(我不认为)。

答案 2 :(得分:9)

您可以通过为set设置私有访问修饰符来实现自动属性读取

public bool Property {get; private set;}

仍然定义了setter,但在定义属性的类之外它不再可见。另外,将setter定义为internal是有用的,这样可以在同一个程序集中轻松设置属性,但不能由外部调用者设置。

答案 3 :(得分:2)

属性可以是只读的,而不是自动属性。

自动属性需要getset,对于只读属性来说,set没有任何意义。

您可以通过定义get将常规属性定义为只读属性 - 但是,即使getset对自动属性的要求不是exists - 无法自动定义只读属性,因为您必须知道支持字段才能在内部设置它的值(即通过构造函数)。

我想可能有一个模板/宏或在VS中定义的东西来生成这个代码,但它不能成为语言本身的一部分。

答案 4 :(得分:1)

我认为从根本上说,问题是属性只是具有可选getter / setter方法的字段的语法糖。自动属性生成支持字段,因此它们需要“setter”,否则将无法设置支持字段的值。由于属性实际上映射到方法而不是字段,因此将它们只读没有任何意义。

即使允许,只读也只能应用于自动属性。对于传统属性,您可以在getter和setter中放置任意代码。即使只能在类的构造函数中调用setter,getter仍然可以根据您决定放入其中的逻辑来改变该值。这完全不符合 readonly 的概念,因此需要不同的语法规则并支持自动/传统属性。由于存在一种机制 - 使用仅定义了getter的传统属性和引用问题中的只读后备字段 - 我认为没有必要弄清属性语法并且可能通过相当简单和直接的实现引入混淆使用当前的语言结构。

答案 5 :(得分:0)

如果属性具有私有集,那么它只能从外部读取,即:

string _name;
public string Name
{
     get{ return _name; }
     private set { _name = value; }
}

或者,如果它根本没有设置器,它可以是只读的,即:

string _name;
public string Name
{
     get{ return _name; }
}

答案 6 :(得分:0)