C# 中的不可变和只读是什么意思?
无法更改不可变对象的值是否正确?
我想了解关于 readonly
的两个场景:
如果我有一个集合并将其标记为
readonly
,如下所示。我还可以调用_items.Add
吗?私有只读 ICollection
; _项目; 对于以下变量,如果稍后我调用
_metadata.Change
,这将更改Metadata
实例中几个成员变量的内部值。_metadata
仍然不可变吗?私有只读元数据_metadata;
对于上面的两个变量,我完全理解我不能在初始化程序和构造函数之外直接为它们分配新值。
Is it correct that it is not possible to change the value of an immutable object?
I have two scenarios regarding readonly
that I want to understand:
What if I have a collection and mark it as
readonly
, like the following. Can I still call_items.Add
?private readonly ICollection<MyItem> _items;
And also for the following variable, if later on I call
_metadata.Change
which will change the internal values of a couple member variable in theMetadata
instance. Is_metadata
still immutable?private readonly Metadata _metadata;
For both variables above, I totally understand that I can't directly assign new values to them outside of initializer and constructors.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
我建议您阅读 Eric Lippert 的系列博客文章。第一部分是 C# 中的不变性第一部分:不变性的种类。一如既往,信息非常丰富且乐于助人。该系列详细描述了变量“只读”、“不可变”等的含义。
通常,
readonly
仅意味着您无法在构造函数外部重新分配字段。只要字段保持相同的实例,字段本身就可以修改。所以是的,您可以将元素添加到存储在readonly
字段中的集合中。关于可变性,这更复杂,这在一定程度上取决于您考虑的可变性类型。当
Metadata
内部值是引用并且这些引用本身(它指向的实例)不会更改时,您可以说Metadata
保持不变。但它在逻辑上发生了变异。请参阅 Eric 的帖子以获取更多见解。I suggest you to read the series of blog posts by Eric Lippert. The first part is Immutability in C# Part One: Kinds of Immutability. Very informative and helpful, as always. The series describes what does it mean for a variable to be readonly, immutable etc. in details.
Generally,
readonly
means only that you can't re-assign a field outside the constructor. The field itself can be modified as long as it stays the same instance. So yes, you can add elements to the collection stored inreadonly
field.About mutability, this is more complex and it depends a bit what kind of mutability you consider. When
Metadata
internal values are references and those references itself (the instances it point to) doesn't change, you could sayMetadata
stays not mutated. But it is mutated logically. See Eric's posts for more insights.不可变对象是一旦创建就无法更改的对象。在 C# 中,字符串是不可变的。如果您查看字符串操作例程,您会发现它们都返回一个新的、修改过的字符串并保持原始字符串不变。
这大大方便了字符串处理。当您引用了某个字符串时,您可以确定没有其他人会在您脚下意外地更改它。
readonly
是另一回事。这意味着引用一旦设置就无法更改,并且只能在对象构造期间设置。在您的示例中,您可以更改_items
的内容或_metadata
的属性,但不能将另一个ICollection
分配给_items
成员或_metadata
的另一个Metadata
实例。readonly
在对象的引用上设置。不变性是对象本身的属性。这些可以自由组合。为了确保属性不以任何方式更改,它应该是对不可变对象的只读引用。An immutable object is one that cannot be changed, once created. In C# strings are immutable. If you look at the string manipulation routines you can see that all of them return a new, modified, string and leaves the original string unchanged.
This facilitates the string handling considerably. When you have a reference to a string, you can be sure that noone else will unexpectedly change it under your feet.
readonly
is something else. It means that the reference cannot be changed, once set and that it can only be set during object construction. In your examples you can change the contents of_items
or the properties of_metadata
, but you cannot assign anotherICollection<MyItem>
to the_items
member or anotherMetadata
instance to_metadata
.readonly
is set on the reference to an object. Immutability is a property of the object itself. These can be freely combined. To make sure that a property is not changed in any way, it should be a readonly reference to an immutable object.将字段标记为只读意味着您无法更改该字段的值。它与那里物体的内部状态无关。在您的示例中,虽然您无法将新的元数据对象分配给 _metadata 字段,也无法将新的 ICollection 分配给 _items 字段(即构造函数之外),但您可以更改存储在中的现有对象的内部值那些领域。
Marking a field as read-only only means that you cannot change the value of that field. It has no bearing on the internal state of the object there. In your examples, while you would not be able to assign a new metadata object to the _metadata field, nor a new ICollection to the _items field (outside of a constructor that is), you can change the internal values of the existing objects stored in those fields.
没有什么可以阻止您改变存储在
readonly
字段中的对象。因此,您可以在构造函数/初始化程序之外调用_items.Add()
和metadata._Change()
。readonly
仅阻止您在构建后为这些字段分配新值。There is nothing preventing you from mutating an object stored in a
readonly
field. So you CAN call_items.Add()
andmetadata._Change()
outside the constructor/initializer.readonly
only prevents you from assigning new values to those fields after construction.私有只读 ICollection_items;
不阻止添加项目。这只是防止
_items
被重新分配。_metadata
也是如此。_metadata
的可访问成员可以更改 -_metadata
无法重新分配。private readonly ICollection<MyItem> _items;
Does not prevent items from being added. This simply prevents
_items
from being re-assigned. The same is true for_metadata
. Accessible members of_metadata
can be changed -_metadata
cannot be re-assigned.readonly 关键字适用于变量 - 这意味着您不能为其分配另一个值,但您可以更改其内部状态。这就是为什么您可以更改集合的项目,但无法将新集合分配给变量。
The readonly keyword applies to a variable - this means you can't assign another value to it, but you can alter its internal state. That's why you can alter a collection's items but you can't assign a new collection to the variable.
在像 C++ 这样的语言中,关键字“const”有很多不同的用法,开发人员可以很容易地传递常量参数以及常量值的常量指针。
这在 C# 中并不容易。
我们需要根据定义构建不可变类,这意味着一旦创建实例,就无法以编程方式更改它。
由于关键字final 及其用法,Java 的方法比C# 更简单一些。
让我们考虑这个例子,看看它是多么不可变。
你可以像这样使用它
In languages like C++ there are quite a few different uses of the keyword "const", it is partly easy for developers to pass constant parameters and also constant pointers of constant values.
That is not easy in C#.
We need to build immutable class by definition, which means Once an instance is created, there is no way it can be changed programmatically.
Java has a little easier way than C# because of the keyword final and its usages.
Lets consider this example and see how immutable it is..
You can use it like this