.net不可变集合已经正式发布

author author     2022-12-05     199

关键词:

微软基础类库(Base Class Library)团队已经完成了​​.NET不可变集合​​的正式版本,但不包括ImmutableArray。与其一起发布的还包括针对其它不可变对象类型的设计指南。

如果你需要在多个线程中安全地共享集合,并且允许每个线程在需要时对其内容进行改变。这种场景就是不可变集合所设计的初衷。只读集合在使用时需要复制集合中的全部内容,而新的不可变集合可以以一种更高性能的方式从一个现有集合中进行创建。

使用不可变集合需要特别当心,因为你很容易错误地写成“list.Add(item)”,而正确的方法是“list = list.Add(item)”。甚至编译器也可能产生类似的错误,这也是为什么不可变集合不支持构造函数的原因。考虑以下代码:

list = new ImmutableList<int> 1, 2, 3;

在编译后会产生以下代码:

temp = new ImmutableList(); temp.Add(1); temp.Add(2) temp.Add(3) list = temp;

由于3次Add方法的结果都被丢弃,最终整个集合包含的项数目为0,而不是期望中的3。

不可变对象指南

Immo Lendwerth建议,当你在创建自己的不可变对象时,在其中加入适当的WithXxx方法。对简单的对象来说,为每一个属性创建一个WithXxx方法即可。当属性值需要变化时,该方法会返回当前对象的一个拷贝。

如果某属性代表了一个结合,那么这种模式就需要一点变化。以下这段代码来自Immo的​​发布声明​​:

class Order

public Order(IEnumerable<OrderLine> lines)

Lines = lines.ToImmutableList();

public ImmutableList<OrderLine> Lines get; private set;
public Order WithLines(IEnumerableOrderLine> value)

return Object.ReferenceEquals(Lines, value)
? this
: new Order(value);

如你所见,WithLines方法可接受任意IEnumerable。因此你可以传递一个新创建的ImmutableList对象,或者是某个LINQ表达式的结果。这种方式已经足以满足需求了,不过他还建议提供某些辅助方法:

class Order

//...
public Order AddLine(OrderLine value)

return WithLines(Lines.Add(value));

public Order RemoveLine(OrderLine value)

return WithLines(Lines.Remove(value));

public Order ReplaceLine(OrderLine oldValue, OrderLine newValue)

return oldValue == newValue
? this
: WithLines(Lines.Replace(oldValue, newValue));

ImmutableArray被移除

由于性能方面的原因,ImmutableArray从最终的发布版本中被移除。其原因是:为了满足内存性能指标,ImmutableArray必须设计成一个值对象,并且为了保持值对象的语义,ImmutableArray的默认实例必须表现为一个空数组形式。不幸的是,为了达到这一点,对空值的检测(null check)会使得C#无法移除对数组边界的检测,而这一点是为达到良好CPU性能的一个重要考虑事项。

由于ImmutableArray类对于Roslyn编译器项目非常重要,设计者曾考虑删除会导致性能问题的空值检测功能,但又因此产生了另外的问题,​​Immo这样写道​​:

由于所有的值类型都有一个自动产生的默认构造函数,它会将该值类型初始化为它的默认状态,而ImmutableArray<T>的默认值是空,它的底层数组实现则为null。因此,AddRange方法的实现会因为NullReferenceException的产生而崩溃。

这一问题还表现在其它一些地方,由于ImmutableArray<T>实现了某些集合接口(例如IEnumerable和IReadOnlyList),因此你可以把它传递给某些接受这种接口的方法。由于这种接口引用是非空的,使用者在调用它的方法或者属性时不会考虑到有可能产生NullReferenceException。

基础类库团队并未放弃这个项目,他们还在研究其它设计方式,以争取让ImmutableArray重新亮相。

查看英文原文:​.NET Immutable Collections Ready for Production​




不可变集合与不可修改集合

】不可变集合与不可修改集合【英文标题】:ImmutablevsUnmodifiablecollection【发布时间】:2012-02-1202:56:33【问题描述】:来自CollectionsFrameworkOverview:不支持修改操作的集合(例如add、remove和clear)被称为不可修改。不可修改的集合是... 查看详情

Scala 集合中的可变与不可变

】Scala集合中的可变与不可变【英文标题】:mutablevs.immutableinScalacollections【发布时间】:2012-01-0709:57:55【问题描述】:我对Scala还很陌生,正在尝试了解集合层次结构。我看到“可变”和“不可变”集合之间存在区别,但我不明... 查看详情

不可变集合被视为可变集合。无法使用 Collections.max

】不可变集合被视为可变集合。无法使用Collections.max【英文标题】:ImmutableCollectionTreatedasMutable.CannotuseCollections.max【发布时间】:2021-01-1223:15:38【问题描述】:我正在使用Camera2API,我正在尝试检索最大的可用图像尺寸。我想使... 查看详情

Doctrine 2 中的不可变集合?

】Doctrine2中的不可变集合?【英文标题】:ImmutablecollectionsinDoctrine2?【发布时间】:2011-09-1023:22:55【问题描述】:我正在寻找一种从Doctrine2中的域对象返回不可变集合的方法。让我们从doc中的这个示例开始:classUser//...publicfunction... 查看详情

使用不可变集合的上限

】使用不可变集合的上限【英文标题】:Usingupper-boundsforimmutablecollections【发布时间】:2021-09-0508:14:15【问题描述】:我正在尝试创建一个可以采用immutable.Seq的任何后代的类型参数的方法。这是我到目前为止得到的:defwriteSomeData... 查看详情

guava集合--immutable(不可变)集合(代码片段)

 所谓不可变集合,顾名思义就是定义了之后不可修改的集合。一.为什么要使用不可变集合不可变对象有很多优点,包括:当对象被不可信的库调用时,不可变形式是安全的;不可变对象被多个线程调用时,不存在竞态条件... 查看详情

不可变 JS - 将地图集合转换为列表

】不可变JS-将地图集合转换为列表【英文标题】:ImmutableJS-convertingacollectionofMapstoaList【发布时间】:2021-08-2010:35:50【问题描述】:我正在从事的项目中具有以下结构(使用不可变的JS):data:[name:\'john\',surname:\'smith\',children:[name:\... 查看详情

在 Scala 中添加不可变集合时,幕后发生了啥?

】在Scala中添加不可变集合时,幕后发生了啥?【英文标题】:WhatgoesonbehindthesceneswhenaddingimmutablecollectionsinScala?在Scala中添加不可变集合时,幕后发生了什么?【发布时间】:2018-01-2603:59:47【问题描述】:在Scala中工作时,我遇到... 查看详情

scala学习(集合01)(代码片段)

文章目录数组不可变数组可变数组可变数组和不可变数组转换Seq集合不可变List可变List可变集合和不可变集合转换Set集合不可变Set可变SetMap集合不可变Map可变Map数组不可变数组packagelearn04objectScalaCollectiondefmain(args:Array[String]):Unit... 查看详情

scala学习(集合01)(代码片段)

文章目录数组不可变数组可变数组可变数组和不可变数组转换Seq集合不可变List可变List可变集合和不可变集合转换Set集合不可变Set可变SetMap集合不可变Map可变Map数组不可变数组packagelearn04objectScalaCollectiondefmain(args:Array[String]):Unit... 查看详情

ReadOnlyCollection vs Liskov - 如何正确建模可变集合的不可变表示

】ReadOnlyCollectionvsLiskov-如何正确建模可变集合的不可变表示【英文标题】:ReadOnlyCollectionvsLiskov-Howtocorrectlymodelimmutablerepresentationsofamutablecollection【发布时间】:2012-11-2822:26:44【问题描述】:里氏替换原则要求子类型必须满足超类... 查看详情

不可变集合到“序列化”字符串

】不可变集合到“序列化”字符串【英文标题】:Immutablecollectionto"serialized"string【发布时间】:2018-07-1204:45:24【问题描述】:我希望采用不可变结构并将其字符串化为磁盘上的文件,以便可以将其重新评估为等效结构。... 查看详情

scala集合

目录1.集合简介 1.1scala的集合有三大类:1.2不可变集合关系一览:IndexedSeq和LinearSeq的区别:1.3可变集合关系继承图:2.数组2.1不可变数组(Array)2.2可变数组(ArrayBuffer)2.3不可变数组和可变数组的... 查看详情

速查objc中可变集合和不可变集合的遍历性能(代码片段)

次数:5,000,000 NSMutableArray//0.131999/0.116085/0.112128NSArray//0.116842/0.111675/0.108623NSMutableSet//0.169277/0.144648NSSet//0.183578/0.129827 可以看出来不可变集合的forin遍历大概快10~20%。这是由于不可变集合在forin的 查看详情

关于集合

...et)的成员通常被称做集合元素。集合有两种不同的类型,可变集合(set)和不可变集合(frozenset)。对于可变集合,你可以添加和删除元素。对不可变集合则不允许这样做。可变集合不是可hash的,不可变集合则正好相反,他们有hash值... 查看详情

Scala 中 val 可变与 var 不可变

】Scala中val可变与var不可变【英文标题】:val-mutableversusvar-immutableinScala【发布时间】:2012-07-0808:24:19【问题描述】:Scala中是否有关于何时将val与可变集合一起使用以及何时将var与不可变集合一起使用的指南?或者你真的应该以... 查看详情

[googleguava]2.1-不可变集合(代码片段)

...s=ImmutableSet.copyOf(bars);//defensivecopy!1314 为什么要使用不可变集合不可变对象有很多优点,包括:当对象被不可信的库调用时,不可变形式是安全的;不可变对象被多个线程调用时,不存在竞态条件问题不可变集合不需要考虑变... 查看详情

线程安全集合(代码片段)

>>返回《C#并发编程》1.简介2.不可变栈和队列3.不可变列表4.不可变Set集合5.不可变字典6.线程安全字典7.阻塞队列8.阻塞栈和包9.异步队列10.异步栈和包11.阻塞/异步队列1.简介不可变集合不可变集合之间通常共享了大部分存储... 查看详情