不要将可变类型的实例分配给只读字段.
使用可变类型创建的对象可以在创建后进行修改.例如,数组和大多数集合是可变类型,而Int32,Uri和String是不可变类型.对于包含可变引用类型的字段,只读修饰符可防止字段值被覆盖但不保护可变类型不被修改.
这简单地重述了readonly的行为,但没有解释为什么使用readonly是不好的.其含义似乎是许多人不理解"只读"的含义,并错误地认为只读字段是不可改变的.实际上,它建议使用"readonly"作为代码文档,指示深层不变性 - 尽管编译器无法强制执行此操作 - 并且禁止将其用于其正常功能:确保字段的值在之后不会发生变化对象已经构建.
我对使用"readonly"来表示除编译器理解的正常含义之外的其他内容感到不安.我觉得它鼓励人们误解"只读"的含义,并且期望它意味着代码作者可能不想要的东西.我觉得它排除了在可能有用的地方使用它 - 例如,表明两个可变对象之间的某些关系在其中一个对象的生命周期内保持不变.假设读者不理解"只读"的含义这一概念似乎与微软的其他建议相矛盾,例如FxCop的"不要初始化不必要"规则,该规则假定您的代码的读者是该语言的专家并且应该知道(例如)bool字段被自动初始化为false,并且阻止您提供显示"是,这已被有意识地设置为false的冗余;我不会忘记初始化它".
那么,首先,为什么Microsoft建议不要使用readonly来引用可变类型?我也有兴趣知道:
Ant*_*ram 25
看起来很自然,如果一个字段是只读的,你会发现无法改变它或与它有关的任何东西.如果我知道Bar是Foo的一个只读领域,我显然不会说
Foo foo = new Foo();
foo.Bar = new Baz();
Run Code Online (Sandbox Code Playgroud)
但我可以说呀
foo.Bar.Name = "Blah";
Run Code Online (Sandbox Code Playgroud)
实际上,如果对象支持Bar是可变的.微软只是通过建议readonly字段由不可变对象支持来推荐反对这种微妙的,违反直觉的行为.
Dan*_*Tao 21
我完全赞成你的,我也有时用readonly在我的代码为可变引用类型.
举个例子:我可能有一些private或protected成员-说,一List<T>-我一类的在其所有的荣耀可变方法中使用(调用Add,Remove等等).我可能只是想设置一个保护措施,以确保无论如何,我总是处理同一个对象.这可以保护我和其他开发人员不做一些愚蠢的事情:即将成员分配给新对象.
对我来说,这通常是使用私有set方法的属性的一个更好的选择.为什么?因为readonly装置不能甚至由基类的实例化后改变的值,.
换句话说,如果我有这个:
protected List<T> InternalList { get; private set; }
Run Code Online (Sandbox Code Playgroud)
然后我仍然可以设置InternalList = new List<T>();我的基类中的代码中的任意点.(这对我来说需要一个非常愚蠢的错误,是的;但它仍然是可能的.)
另一方面,这个:
protected readonly List<T> _internalList;
Run Code Online (Sandbox Code Playgroud)
使它明确无误,_internalList 只能引用一个特定的对象(_internalList构造函数中设置的对象).
所以我就在你身边.一个人应该避免使用readonly可变引用类型的想法对我个人来说是令人沮丧的,因为它基本上预先假定对readonly关键字的误解.
不要将可变类型的实例分配给
readonly字段.
我快速浏览了" 框架设计指南"一书(第161-162页),它基本上说明了您自己已经注意到的内容.Joe Duffy还有一个额外的评论解释了指南的存在理由:
本指南试图保护您的目的是相信您已经暴露了一个深层不可变的对象图,而事实上它很浅,然后编写假设整个图形是不可变的代码.
- 乔达菲
我个人认为该关键字readonly名称很差.它只指定引用的常量而不是引用对象的常量这一事实很容易产生误导性的情况.
我认为如果readonly使引用的对象也是不可变的,而不仅仅是引用,那将是更可取的,因为这是关键字所暗示的.
为了纠正这种不幸的情况,制定了指南.虽然我认为它的建议是从声音的人的观点(这并不总是显而易见的,其类型是可变的,这也不是没有看他们的定义,这个词暗示深不变性),我有时想,当谈到为了声明常量,C#将提供类似于C++提供的自由,您可以const在指针上,或在指向对象上,或在两者上或在任何内容上定义.