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

本文关键字:是什么 意思 只读 不可变 | 更新日期: 2023-09-27 18:03:37

是正确的,它是不可能改变一个不可变对象的值?

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

  1. 如果我有一个集合并将其标记为readonly,如下所示。我还能打给_items.Add吗?

    private readonly ICollection<MyItem> _items;
    
  2. 对于以下变量,如果稍后我调用_metadata.Change,这将改变Metadata实例中一对成员变量的内部值。_metadata仍然是不可变的吗?

    private readonly Metadata _metadata;
    

对于上面的两个变量,我完全理解我不能在初始化器和构造函数之外直接给它们赋新值。

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

我建议你阅读Eric Lippert的系列博客文章。第一部分是c#中的不变性,第一部分:不变性的种类。非常有用的信息和帮助,一如既往。本系列详细描述了只读不可变等变量的含义。

一般来说,readonly只意味着你不能在构造函数之外重新分配一个字段。字段本身可以被修改,只要它保持相同的实例。所以,是的,您可以将元素添加到存储在readonly字段中的集合中。

关于可变性,这是更复杂的,它取决于你考虑什么样的可变性。当Metadata内部值是引用并且这些引用本身(它指向的实例)没有改变时,您可以说Metadata保持不变。但是它在逻辑上是变异的

将字段标记为只读仅意味着不能更改该字段的值。它与物体的内部状态无关。在您的示例中,虽然您不能将新的元数据对象分配给_metadata字段,也不能将新的iccollection分配给_items字段(即在构造函数之外),但您可以更改存储在这些字段中的现有对象的内部值。

不可变对象是一旦创建就不能更改的对象。在c#中字符串是不可变的。如果你看一下字符串操作例程,你会发现它们都返回一个新的、修改过的字符串,而原始字符串保持不变。

这大大简化了字符串处理。当你有一个对字符串的引用时,你可以确保没有其他人会在你的脚下意外地改变它。

readonly是另一回事。这意味着引用一旦设置就不能更改,并且只能在对象构造期间设置。在您的示例中,您可以更改_items的内容或_metadata的属性,但您不能将另一个ICollection<MyItem>分配给_items成员或将另一个Metadata实例分配给_metadata

readonly对对象的引用上设置。不变性是对象本身的属性。这些可以自由组合。为了确保属性不会以任何方式被改变,它应该是对不可变对象的只读引用。

没有什么可以阻止您更改存储在readonly字段中的对象。所以你可以在构造函数/初始化器之外调用_items.Add()metadata._Change()readonly只阻止在构造后给赋新值。

private readonly ICollection<MyItem> _items;

不阻止添加项。这只是防止_items被重新分配。_metadata也是如此。

_metadata的可访问成员可以被修改,_metadata不能被重新分配。
  1. 是的。
  2. 只读不等于不可变。你仍然可以调用_metadata.Change.

readonly关键字适用于变量-这意味着您不能为其分配其他值,但可以更改其内部状态。这就是为什么你可以改变集合的项,但不能给变量赋值一个新的集合。

在像c++这样的语言中,关键字"const"有很多不同的用法,对于开发人员来说,传递常量参数和常量值的常量指针在一定程度上是很容易的。

这在c#中并不容易。我们需要通过定义来构建不可变类,这意味着一旦创建了实例,就无法通过编程方式对其进行更改。

Java有一个比c#更简单的方法,因为关键字final及其用法。

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

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();
        }
    }