只写属性,有什么意义?

Ant*_*ony 53 c# properties

我理解为什么要使用以下语法来使用只读属性:

private int _MyInt;
public int MyInt
{
  get { return _MyInt; }
}
Run Code Online (Sandbox Code Playgroud)

这个例子可能不是最好的例子,因为我认为只读属性真的与readonly变量一起发光,但这不是重点.我不明白的是为什么使用以下语法使用只写属性:

private int _MyInt;
public int MyInt
{
  set { _MyInt = value; }
}
Run Code Online (Sandbox Code Playgroud)

这是各种书籍和教程中描述只读属性的方式.如果设置了变量,你会在概念上阅读一些点,至少在内部的类,但该类中甚至在内部读它,你会被accesssing这样做_MyInt,我觉得违反了封装的精神,性质试图强制执行.相反,为什么不只是使用具有不同访问修改的属性的全部功能来访问它:

private int _MyInt;
public int MyInt
{
  set { _MyInt = value; }
  private get { return _MyInt; }
}
Run Code Online (Sandbox Code Playgroud)

当然可以写出来

public int MyInt { set; private get; }
Run Code Online (Sandbox Code Playgroud)

您仍然可以获得封装,但是限制其他类访问,因此它仍然只能写入外部类.

除非有一种情况,你真诚地希望分配给一个变量,但从未实际访问它,在这种情况下,我肯定会对何时出现这种需求感到好奇.

And*_*are 70

我从来没有遇到过只写属性的有效用例.老实说,如果对于只写属性有一个有效的用例,我认为可以肯定地说解决方案的设计很糟糕.

如果您需要"只写"语义,则应使用方法.例如,另一个用户找到了一个用户对象的示例,该用户对象使用只写属性来设置密码.这是一个糟糕的设计:

class User
{
    public string Password
    {
        set { /* password encryption here */ }
    }
}
Run Code Online (Sandbox Code Playgroud)

啊.这要好得多:

class User
{
    public void SetPassword(string password)
    {
        /* password encryption here */
    }
}
Run Code Online (Sandbox Code Playgroud)

请参阅,读/写属性是一组旨在伪装成字段的方法.它们看起来和感觉就像一块田地.出于这个原因,只读属性是有意义的,因为我们习惯于拥有可以读取但不能更改的字段和变量.但是,没有可写但不可读的相应字段或变量构造.

这就是为什么我认为创建一个使用只写属性的API是不好的做法.它与我认为C#中属性语法的主要目标背道而驰.

编辑:更多哲学......我相信课程有一个功能目的:它们提供了一个容器,用于存储和操作相关数据.以我们的User课程为例 - 该课程将包含与系统中用户相关的所有信息.我们收集所有这些数据并给它们一个名称:user.通过这种方式,我们使用类来创建抽象.User是一种抽象,允许我们推理构成用户的所有单个数据(密码,名称,生日等).

现在有很好的抽象,并且有很糟糕的抽象.我认为只写属性是错误的抽象,因为你允许某人输入数据而不是读取数据.你为什么不允许这样做?很可能是因为传入的信息已经以某种方式进行了转换,使得传球者无法理解.

所以这意味着按定义只写属性必须创建调用者看不到的副作用(因为如果他们能看到它们,那么就没有理由让属性只写).用于设置具有副作用的值的C#语言中的最佳构造是方法.

我强烈建议不要使用只写属性,因为您的API的使用者会发现它们令人困惑和令人沮丧.即使您为此语法找到了有效的用例,也无法证明其使用的合理性.


编辑:以下是.Net框架设计指南 - 开发类库 - > 成员设计指南 - > 属性设计的官方建议

不提供仅限设置的属性.

如果无法提供属性getter,请使用方法来实现该功能.方法名称应以Set开头,后跟属性名称...

  • 我同意 - 如果你有一些需要进入的信息,但不应该回读,只需使用一种方法. (2认同)

Tho*_*mas 16

有趣的问题.

经过一些谷歌搜索,是我能找到的全部内容:可以使用只写属性在User对象上设置密码.由于密码通常以散列形式存储,因此在设置密码后(并且应该)无法检索密码.


neo*_*pir 11

只写属性的一个用途是支持setter依赖注入.

假设我上课了:

public class WhizbangService {
    public WhizbangProvider Provider { set; private get; }
}
Run Code Online (Sandbox Code Playgroud)

WhizbangProvider不打算被外界访问.我永远不想与之互动service.Provider,这太复杂了.我需要一个像WhizbangService这样的课程作为门面.然而对于二传手,我可以这样做:

service.Provider = new FireworksShow();
service.Start();
Run Code Online (Sandbox Code Playgroud)

该服务开始烟花汇演.或者你可能更喜欢看水和灯光表演:

service.Stop();
service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds);
service.Start();
Run Code Online (Sandbox Code Playgroud)

等等....

  • Setter注入的一种用例是在基类中。如果改为选择构造函数注入,则任何派生类都必须编写构造函数重载。 (2认同)

Ste*_*ner 6

我能看到的一个常见情况是,您是否只希望调用者能够获得您的属性的转换版本.例如:

public int MyInt { set; }
public string MyIntAsString 
{ 
   get { return this.MyInt.ToString(); } 
}
Run Code Online (Sandbox Code Playgroud)

显然,这不是一个真实的例子,但你得到了图片.

编辑:

在阅读了Thomas的示例用例之后,真正的"转换"类型场景可能是检索只写属性的加密版本:

private string password;

public string ClearPassword { set { this.password = value; }
public string EncryptedPassword
{
   get { return Encrypt(password); }
}
Run Code Online (Sandbox Code Playgroud)