C# 中的不可变和只读是什么意思?

发布于 2024-11-27 00:55:03 字数 470 浏览 1 评论 0原文

无法更改不可变对象的值是否正确?

我想了解关于 readonly 的两个场景:

  1. 如果我有一个集合并将其标记为 readonly,如下所示。我还可以调用 _items.Add 吗?

    私有只读 ICollection; _项目;
    
  2. 对于以下变量,如果稍后我调用 _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:

  1. 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;
    
  2. 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 the Metadata 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

万劫不复 2024-12-04 00:55:03

我建议您阅读 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 in readonly 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 say Metadata stays not mutated. But it is mutated logically. See Eric's posts for more insights.

日裸衫吸 2024-12-04 00:55:03

不可变对象是一旦创建就无法更改的对象。在 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 another ICollection<MyItem> to the _items member or another Metadata 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.

删除→记忆 2024-12-04 00:55:03

将字段标记为只读意味着您无法更改该字段的值。它与那里物体的内部状态无关。在您的示例中,虽然您无法将新的元数据对象分配给 _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.

烟柳画桥 2024-12-04 00:55:03

没有什么可以阻止您改变存储在 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() and metadata._Change() outside the constructor/initializer. readonly only prevents you from assigning new values to those fields after construction.

梦明 2024-12-04 00:55:03

私有只读 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.

夏了南城 2024-12-04 00:55:03
  1. 是的。
  2. 只读并不等于不可变。您仍然可以调用 _metadata.Change。
  1. Yes.
  2. Readonly doesn't equal to immutable. You can still call _metadata.Change.
不弃不离 2024-12-04 00:55:03

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.

够钟 2024-12-04 00:55:03

在像 C++ 这样的语言中,关键字“const”有很多不同的用法,开发人员可以很容易地传递常量参数以及常量值的常量指针。

这在 C# 中并不容易。
我们需要根据定义构建不可变类,这意味着一旦创建实例,就无法以编程方式更改它。

由于关键字final 及其用法,Java 的方法比C# 更简单一些。

让我们考虑这个例子,看看它是多么不可变。

public sealed class ImmutableFoo
    {
        private ImmutableFoo()
        {

        }

        public string SomeValue { get; private set; }
        //more properties go here

        public sealed class Builder
        {
            private readonly ImmutableFoo _instanceFoo = new ImmutableFoo();
            public Builder SetSomeValue(string someValue)
            {
                _instanceFoo.SomeValue = someValue;
                return this;
            }

            /// Set more properties go here
            /// 

            public ImmutableFoo Build()
            {
                return _instanceFoo;
            }
        }
    }

你可以像这样使用它

public class Program
    {
        public static void Main(string[] args)
        {
            ImmutableFoo foo = new ImmutableFoo.Builder()
                .SetSomeValue("Assil is my name")
                .Build();

            Console.WriteLine(foo.SomeValue);
            Console.WriteLine("Hit enter to terminate");
            Console.ReadLine();
        }
    }

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..

public sealed class ImmutableFoo
    {
        private ImmutableFoo()
        {

        }

        public string SomeValue { get; private set; }
        //more properties go here

        public sealed class Builder
        {
            private readonly ImmutableFoo _instanceFoo = new ImmutableFoo();
            public Builder SetSomeValue(string someValue)
            {
                _instanceFoo.SomeValue = someValue;
                return this;
            }

            /// Set more properties go here
            /// 

            public ImmutableFoo Build()
            {
                return _instanceFoo;
            }
        }
    }

You can use it like this

public class Program
    {
        public static void Main(string[] args)
        {
            ImmutableFoo foo = new ImmutableFoo.Builder()
                .SetSomeValue("Assil is my name")
                .Build();

            Console.WriteLine(foo.SomeValue);
            Console.WriteLine("Hit enter to terminate");
            Console.ReadLine();
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文