微软基础类库(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

.NET不可变集合已经正式发布的更多相关文章

  1. 在sql server中建存储过程,如果需要参数是一个可变集合怎么处理?

    在sql server中建存储过程,如果需要参数是一个可变集合的处理 原存储过程,@objectIds 为可变参数,比如 110,98,99 ALTER PROC [dbo].[Proc_totalS ...

  2. Guava学习笔记:Immutable(不可变)集合

    不可变集合,顾名思义就是说集合是不可被修改的.集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变. 为什么要用immutable对象?immutable对象有以下的优点: 1.对不可靠的客 ...

  3. 不可变集合 Immutable Collections

    例子 public static final ImmutableSet<String> COLOR_NAMES = ImmutableSet.of( "red", &q ...

  4. [Guava源码分析]ImmutableCollection:不可变集合

    摘要: 我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3888557.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的 ...

  5. [Guava学习笔记]Collections: 不可变集合, 新集合类型

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3843386.html,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体验 ...

  6. [Guava官方文档翻译] 7. Guava的Immutable Collection(不可变集合)工具 (Immutable Collections Explained)

    我的技术博客经常被流氓网站恶意爬取转载.请移步原文:http://www.cnblogs.com/hamhog/p/3538666.html ,享受整齐的排版.有效的链接.正确的代码缩进.更好的阅读体 ...

  7. 洗礼灵魂,修炼python(7)--元组,集合,不可变集合

    前面已经把列表的基本用法讲解完 接着讲python的几大核心之--元组(tuple) 1.什么是元组? 类似列表,但为不可变对象,之前提到列表是可变对象,所谓可变对象就是支持原处修改,并且在修改前后对 ...

  8. Immutable(不可变)集合

    Immutable(不可变)集合 不可变集合,顾名思义就是说集合是不可被修改的.集合的数据项是在创建的时候提供,并且在整个生命周期中都不可改变. 为什么要用immutable对象?immutable对 ...

  9. java代码之美(4)---guava之Immutable(不可变)集合

    Immutable(不可变)集合 一.概述 guava是google的一个库,弥补了java语言的很多方面的不足,很多在java8中已有实现,暂时不展开.Collections是jdk提供的一个工具类 ...

随机推荐

  1. Linux中文件颜色所代表的属性和颜色

    绿色文件: 可执行文件,可执行的程序    红色文件:压缩文件或者包文件   蓝色文件:目录   白色文件:一般性文件,如文本文件,配置文件,源码文件等    浅蓝色文件:链接文件,主要是使用ln命令 ...

  2. JsonHelper MergeJsonTemplate

    namespace Test { using Newtonsoft.Json; using System; using System.Collections.Generic; using System ...

  3. 创建Unity3D的MacOS Plugin的正确姿势

    http://www.tedlindstrom.se/how-to-link-dylibs-into-unity3d/ I was roaming around the net looking for ...

  4. 限制input只能输入金额(类似:100.00|100.9|100)

    $(".inputmoney").keyup(function () {    var reg = $(this).val().match(/\d+\.?\d{0,2}/);    ...

  5. Node.js之NPM工具使用

    1.NPM介绍:包管理工具 (1)允许用户从NPM服务器下载别人编写的第三方包到本地石使用 (2)允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用 (3)允许用户将自己编写的包或命令行程 ...

  6. iOS 真机测试时报错:Provisioning profile "iOS Team Provisioning Profile: XXX” doesn't include the currently selected device “XXX”.

    这几天因工作需要,去给客户演示iOS项目打包的过程.之前演示都是顺利的,但后来客户自己操作时打电话说遇到了问题,出现报错. 就过去看了一下,发现一个很陌生的错误提示: The operation co ...

  7. R语言绘制空间热力图

    先上图 R语言的REmap包拥有非常强大的空间热力图以及空间迁移图功能,里面内置了国内外诸多城市坐标数据,使用起来方便快捷. 开始 首先安装相关包 install_packages("dev ...

  8. WPF-禁止二次启动

    App.xaml.cs protected override void OnStartup(StartupEventArgs e) { //禁止二次启动 this.Startup += new Sta ...

  9. 整理ViewController的生命周期和加载过程

    按照执行顺序排列 - initWithCoder:通过nib文件初始化时触发 - awakeFromNib:nib文件被加载的时候,会发送一个awakeFromNib的消息到nib文件中的每个对象 p ...

  10. List<T>Find方法,FindAll方法,Contains方法,Equals方法

    假如传入的T是一个类, List<MessageInfos> MessageInfos = new List<MessageInfos>(); MessageInfos= Me ...