微软基础类库(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. DataGridView回车焦点横向移动

    protected override bool ProcessCmdKey(ref Message msg, Keys keyData)        {            if (keyData ...

  2. C# ORM中Dto Linq Expression 和 数据库Model Linq Expression之间的转换

    今天在百度知道中看到一个问题,研究了一会便回答了: http://zhidao.baidu.com/question/920461189016484459.html 如何使dto linq 表达式转换 ...

  3. ZooKeerper学习之Watcher

    ZooKeeper为我们提供了用于监视结点变化的Watcher机方法制: 1.可以注册Watcher的方法:getData().exists().getChildren().我们可以通过查看ZooKe ...

  4. XACML学习

    学习的网站: http://www.cinlk.com/2015/07/27/xacml/ http://www.cinlk.com/2015/08/22/swiftabac/ http://blog ...

  5. Beginning Scala study note(8) Scala Type System

    1. Unified Type System Scala has a unified type system, enclosed by the type Any at the top of the h ...

  6. Mysql数据库的使用总结之Innodb简介

     最近在对开发的软件的服务器部分制作安装包,但服务器部分需要有mysql数据库的支持.因此,采用免安装版的mysql策略:将mysql数据库需要的文件在安装程序中进行设置和打包即可.但也遇到了很多问题 ...

  7. redmine整合GIT版本库

    redmine整合GIT版本库   服务器的环境: Ubuntu 11.10 64位 Redmine 1.4.5.stable.10943 git version 1.7.5.4 + gitolite ...

  8. C# Current thread must be set to single thread apartment (STA) mode before OLE calls can be made

    将箭头指向部分替换为编译器报错的内容即可. 参考文章:https://www.experts-exchange.com/questions/28238490/C-help-needed-Current ...

  9. 使用 Redis 实现排行榜功能

    排行榜功能是一个很普遍的需求.使用 Redis 中有序集合的特性来实现排行榜是又好又快的选择. 一般排行榜都是有实效性的,比如“用户积分榜”.如果没有实效性一直按照总榜来排,可能榜首总是几个老用户,对 ...

  10. [BZOJ1562][ZJOI2007] 最大半连通子图

    Description Input 第一行包含两个整数N,M,X.N,M分别表示图G的点数与边数,X的意义如上文所述.接下来M行,每行两个正整数a, b,表示一条有向边(a, b).图中的每个点将编号 ...