只写属性,有什么意义?
我明白为什么要使用以下语法使用只读属性:
private int _MyInt; public int MyInt { get { return _MyInt; } }
这个例子可能并不是最好的例子,因为我认为只读属性真的与readonly
variables一起发光,但这不是重点。 我不明白为什么使用只写属性使用以下语法:
private int _MyInt; public int MyInt { set { _MyInt = value; } }
这是在各种书籍和教程中描述只读属性的方式。 如果你设置了这个variables,你至less可以在内部对它进行概念性的读取,至less在内部读取它,甚至在内部读取它,通过访问_MyInt
,我觉得这违反了封装的精神,执行。 相反,你为什么不使用不同访问修改的属性的全部权力来访问它:
private int _MyInt; public int MyInt { set { _MyInt = value; } private get { return _MyInt; } }
哪一个当然可以写
public int MyInt { set; private get; }
你仍然可以获得封装,但是限制其他类访问,所以它仍然只写外部类。
除非有一个情况,你真的想分配给一个variables,但从来没有实际访问它,在这种情况下,我一定会好奇这种需求何时会出现。
我从来没有遇到过只写属性的有效用例。 老实说,如果有一个只写属性的有效用例,我认为可以肯定地说解决schemedevise不好。
如果你需要“只写”语义,你应该使用一个方法。 例如,另一个用户find了一个使用只写属性设置密码的用户对象的例子。 这是一个糟糕的devise:
class User { public string Password { set { /* password encryption here */ } } }
啊。 这好多了:
class User { public void SetPassword(string password) { /* password encryption here */ } }
请参阅读/写属性是一组旨在伪装成字段的方法。 他们看起来和感觉像一个领域。 正因为如此,只读属性才有意义,因为我们习惯于拥有我们可以读取但不能改变的字段和variables。 但是,没有相应的字段或variables结构可写,但不可读。
这就是为什么我相信创build一个使用只写属性的API是不好的做法。 它与我认为是C#中属性语法的主要目标相反。
编辑:更多的哲学…我相信,类服务function的目的:他们提供了一个相关的数据被容纳和操纵的容器。 以我们的User
类为例 – 这个类将保存与系统中用户相关的所有信息。 我们收集所有这些数据,并给他们一个名字: 用户 。 这样我们使用类来创build抽象 。 User
是一种抽象,它使我们能够推断组成用户(密码,姓名,生日等)的所有单个数据片断。
现在有很好的抽象概念,抽象概念也不好。 我相信只写属性是不好的抽象,因为你允许某人input数据而不读取它。 你为什么不接受呢? 很可能是因为已经传递的信息已经以某种方式变化,使得传球者难以理解。
因此,这意味着按定义只写属性必须创build调用者看不到的副作用(因为如果他们能够看到它们,那么将没有理由使该属性为只写)。 C#语言中用于设置具有副作用的值的最佳构造是该方法 。
我强烈build议不要使用只写属性,因为API的使用者会发现它们令人困惑和沮丧。 即使你find这个语法的有效用例,也不能certificate它的用法。
编辑:这是从.Net Framework 开发类库 devise指南 – > 成员devise指南 – > 属性devise的官方build议
不要提供集合属性。
如果无法提供属性getter,请使用方法来实现该function。 方法名称应该以Set开头,接着是属性名称…
有趣的问题。
经过一些Googlesearch之后,我可以find所有这些:一个只写属性可以用来设置一个User
对象的密码。 由于密码通常是以散列forms存储的,因此在设置密码之后(并且应该)无法检索密码。
一个用于只写属性的用途是支持setterdependency injection。
假设我有一堂课:
public class WhizbangService { public WhizbangProvider Provider { set; private get; } }
WhizbangProvider不打算被外部世界访问。 我永远不想与service.Provider
交互,这太复杂了。 我需要像WhizbangService这样的课程来充当门面。 然而,通过二传手,我可以做这样的事情:
service.Provider = new FireworksShow(); service.Start();
这项服务开始了烟花汇演。 或者,也许你更愿意看一场水和灯光秀:
service.Stop(); service.Provider = new FountainDisplay(new StringOfLights(), 20, UnitOfTime.Seconds); service.Start();
等等….
我可以看到一个常见的情况是,如果你只想要一个调用者能够获得你的财产的转换版本。 例如:
public int MyInt { set; } public string MyIntAsString { get { return this.MyInt.ToString(); } }
显然,这不是一个真实的例子,但是你可以得到这张照片。
编辑 :
在阅读Thomas的示例用例之后,真正的“转换”types的场景可能是检索只写属性的encryption版本:
private string password; public string ClearPassword { set { this.password = value; } public string EncryptedPassword { get { return Encrypt(password); } }
我读过的资料提示,如果你真的有一个刚刚创build一个只写属性的情况,你应该考虑把它变成一个方法。 我通常同意。
任何必须以单向方式stream动的信息通过只写属性是有用的。 一般来说,我们写信息的类来stream出或stream出。 在只写的情况下,你必须考虑信息只能stream入而不能stream出的情况。 通常这涉及安全types的信息,因为我们不希望消费者有任何获取安全信息的权限。 密码,CC号码等
当信息不安全的时候,例如,当我们不介意任何人访问它时,我们就会得到通用的get / set模式。 99.9%的时间这是如何使用属性。 由于还有其他的方法,就像容易实现这一点一样,这更像是一个语义结构,而不是任何对称。 其中一个罕见的情况是没有拿出什么东西,你的左边是“为什么他们把它删除了!”。
我能想到的是,因为_myInt显示在intellisense上下文菜单的顶部。
我不认为访问_myInt违反封装的精神, 这是一个类的私人成员领域。 类中的任何代码都应该使用_myInt。 毕竟这是私人的。
对外界唯一重要的是这个阶级的公共契约。 _myInt是这个阶级本身的关注点,而不是面向公众的一部分。
就像我说的 – 当你编码时,用智能感知抓住_myInt更容易。
我敢肯定,这个function只是为了使用只读variables来进行symetry。 正如Aphex含糊地暗示的那样,有些东西没有意义,只是在那里,因为离开它更容易,而不是去除它。
我有一个只写属性的原因。
在.NET Web服务中,我不得不创build一个传统的.ASMX Web服务,因为URI是硬件硬编码的。
我非常喜欢使用Ninject进行dependency injection,使用构造函数注入来满足类可能具有的所有依赖。 大多数情况下,这些依赖关系将被声明为private readonly fieldName
并在构造函数中分配给它。 原因是这个类的依赖关系不是类的责任的一部分,它们是依赖关系。
然而,问题在于,无论使用哪种工厂机制来创buildWeb服务的类实例,都依赖于没有参数的构造函数,这会使我的构造函数注入受到阻碍。
我可以使用来自默认构造函数的调用来重新定向到使用ServiceLocator(反)模式的重载构造函数,但是我并不喜欢这个。
使用Ninject Web扩展,我从Ninject.Web.WebServiceBase
inheritance了我的服务类,并使用了属性注入,标记了Ninject使用[Inject]
属性满足的属性。
回到关于注入服务是类的依赖关系,而不是类的职责,我不希望这些依赖属性被其他类访问,所以我把get属性标记为private。