C#中数组的不可变替代品是什么?

tho*_*ius 5 c# immutability

对于C#中的生产代码,数组的不可变替代品是什么(至少在ImmutableArray处于测试阶段时)?

Jep*_*sen 7

您应该提供更多详细信息,但一个选项是System.Collections.ObjectModel.ReadOnlyCollection<>作为列表/数组.它可以像这样创建:

  var immutable1 = Array.AsReadOnly(new[] { 7, 9, 13, });
  var immutable2 = (new List<int> { 7, 9, 13, }).AsReadOnly();
Run Code Online (Sandbox Code Playgroud)

它是一个包装器IList<>.它不能转换为允许更改基础列表/数组的任何内容.但当然,可以通过反思来达到基础对象.

如果某个地方的其他人改变了"内部"列表/数组,那么它将在ReadOnlyCollection<>包装器中重新连接.没有复制.

这是一种"浅薄"的不变性形式.如果单个项目可以变异(哪个int不能),则包装器不会禁止这样做.


更便宜的事情就是使用IReadOnlyList<out T>协变的接口T(一个额外的优势).a List<T>和a都T[]实现了这个接口.所以:

  IReadOnlyList<int> immutable3 = new[] { 7, 9, 13, };
  IReadOnlyList<int> immutable4 = new List<int> { 7, 9, 13, };
Run Code Online (Sandbox Code Playgroud)

然而,在这种情况下,消费者可以测试immutable3 as IList<int>,例如,或者immutable3 as int[]获得可变对象的"可变类型引用"(没有反射).


但是,Microsoft.Immutable.Collections中存在不可变的类型(例如ImmutableList<>).所以你可以考虑安装它,如果你真的需要它.它不是标准.NET库的一部分,因此您必须单独安装它.


为了详细阐述"浅"的含义,假设你有一个数组,其元素类型本身是可变的.那么无论您使用上述哪种建议,人们仍然可以对条目进行调整.例如:

StringBuilder[] yourArray = { 
    new StringBuilder("All"),
    new StringBuilder("is"),
    new StringBuilder("good"),
    };

var immutable = ImmutableList<StringBuilder>.Empty.AddRange(yourArray);

immutable[0].Insert(0, "NOT ");
immutable[1].Clear();
immutable[2].Append(new string('!', 10000));
Run Code Online (Sandbox Code Playgroud)