Immutable Collections(2)ImmutableList<T>实现原理.(上)
2013-05-06 21:52
302 查看
[b]ImmutableCollections(2)ImmutableList<T>实现原理.(上)[/b]
文/玄魂
ImmutableCollections(1)),我简要说明了不可变集合的基本概念和简单应用。从本篇博文开始,会探讨下几个典型集合类型的内部实现机制。本篇博客主要探讨ImmutableList<T>实现原理。
博文中引用的代码并非是.NET源码,而是反编译得来,不正确之处,还望指教。
处于最顶端的ImmutableList静态类,是ImmutableList<T>类型的构造者,它或者直接返回ImmutableList<T>的Empty属性,或者在Empty的基础上构造ImmutableList<T>实例,比如下面的代码:
SyncRoot是Object类型字段,作为同步锁对象。
Empty直接返回当前集合的单例对象EmptySingleton。
ImmutableList<T>构造函数如下:
ImmutableList<T>的EmptySingleton就是返回的上图中最上面的Node类的EmptyNode。EmptyNode定义如下:
frozen是一个bool类型的变量,表示是否冻结。冻结可以说是不可变集合的一个关键特性,下面也会对此做详细的分析。
height是以当前节点为根的树的高度。
调用EmptySingleton时触发ImmutableList<T>的初始化。
接下来在构造函数中调用Node.EmptyNode。
在Node类的无参构造函数中只初始化了一个变量:
此时Node.EmptyNode实例的各字段值如下图所示:
到此为止第一次初始化结束。
现在测试下带比较器的构造方式,先新建一个TestCompare类:
带初始值的构造函数,实际是调用了Add方法,我将在下一篇博文中单独分析。
本篇博文到此结束,未完,待续。。。。。。
文/玄魂
前言
在上一篇文章(博文中引用的代码并非是.NET源码,而是反编译得来,不正确之处,还望指教。
2.1概述
下图是ImmutableList<T>类型包含的核心字段、属性(并非全部),以及和其他类型的关系。这张图是自动生成的,我直接拿过来没有做什么改动,可能会让人云里雾里,下面我做简要的说明。处于最顶端的ImmutableList静态类,是ImmutableList<T>类型的构造者,它或者直接返回ImmutableList<T>的Empty属性,或者在Empty的基础上构造ImmutableList<T>实例,比如下面的代码:
publicstaticImmutableList<T>Create<T>()
{
returnImmutableList<T>.Empty;
}
publicstaticImmutableList<T>Create<T>(IEqualityComparer<T>equalityComparer)
{
returnImmutableList<T>.Empty.WithComparer(equalityComparer);
}
publicstaticImmutableList<T>Create<T>(Titem)
{
returnImmutableList<T>.Empty.Add(item);
}
ImmutableList静态类下面是核心部分——ImmutableList<T>类型。ImmutableList<T>继承自如下接口:
IImmutableList<T>,IReadOnlyList<T>,IReadOnlyCollection<T>,IList<T>,ICollection<T>,IList,ICollection,IOrderedCollection<T>,IEnumerable<T>,IEnumerable,IImmutableListQueries<T>
其中IImmutableList<T>定义如下:publicinterfaceIImmutableList<T>:IReadOnlyList<T>,IReadOnlyCollection<T>,IEnumerable<T>,IEnumerable
{
IEqualityComparer<T>ValueComparer
{
get;
}
IImmutableList<T>Clear();
boolContains(Tvalue);
intIndexOf(Tvalue);
IImmutableList<T>Add(Tvalue);
IImmutableList<T>AddRange(IEnumerable<T>items);
IImmutableList<T>Insert(intindex,Telement);
IImmutableList<T>InsertRange(intindex,IEnumerable<T>items);
IImmutableList<T>Remove(Tvalue);
IImmutableList<T>RemoveAll(Predicate<T>match);
IImmutableList<T>RemoveRange(IEnumerable<T>items);
IImmutableList<T>RemoveRange(intindex,intcount);
IImmutableList<T>RemoveAt(intindex);
IImmutableList<T>SetItem(intindex,Tvalue);
IImmutableList<T>Replace(ToldValue,TnewValue);
IImmutableList<T>WithComparer(IEqualityComparer<T>equalityComparer);
}
IImmutableListQueries<T>定义如下:internalinterfaceIImmutableListQueries<T>
{
intCount
{
get;
}
ImmutableList<TOutput>ConvertAll<TOutput>(Func<T,TOutput>converter);
voidForEach(Action<T>action);
ImmutableList<T>GetRange(intindex,intcount);
voidCopyTo(T[]array);
voidCopyTo(T[]array,intarrayIndex);
voidCopyTo(intindex,T[]array,intarrayIndex,intcount);
boolExists(Predicate<T>match);
TFind(Predicate<T>match);
ImmutableList<T>FindAll(Predicate<T>match);
intFindIndex(Predicate<T>match);
intFindIndex(intstartIndex,Predicate<T>match);
intFindIndex(intstartIndex,intcount,Predicate<T>match);
TFindLast(Predicate<T>match);
intFindLastIndex(Predicate<T>match);
intFindLastIndex(intstartIndex,Predicate<T>match);
intFindLastIndex(intstartIndex,intcount,Predicate<T>match);
intIndexOf(Titem);
intIndexOf(Titem,intindex);
intIndexOf(Titem,intindex,intcount);
intLastIndexOf(Titem);
intLastIndexOf(Titem,intindex);
intLastIndexOf(Titem,intindex,intcount);
boolTrueForAll(Predicate<T>match);
}
其他接口,是.NET中原有接口,这里就不列举了。IImmutableList<T>的核心行为都定义在这两个接口当中。SyncRoot是Object类型字段,作为同步锁对象。
Empty直接返回当前集合的单例对象EmptySingleton。
ImmutableList<T>构造函数如下:
internalImmutableList()
{
this.root=ImmutableList<T>.Node.EmptyNode;
this.valueComparer=EqualityComparer<T>.Default;
}
privateImmutableList(ImmutableList<T>.Noderoot,IEqualityComparer<T>valueComparer)
{
root.Freeze();
this.root=root;
this.valueComparer=valueComparer;
}
在构造函数中我们又发现两个很重要的类型,Node和IEqualityComparer。IEqualityComparer这里就不解释了,我们重点关注Node,从字面上理解,这是一个表示节点的类,事实上它是ImmutableList<T>的核心,数据的承载和操作都是对Node类的包装。下面我们来看看Node的庐山真面目。2.2Node
Node类继承自三个接口,
internalsealedclassNode:IBinaryTree<T>,IEnumerable<T>,IEnumerable
我们主要关注IBinaryTree<T>,定义如下:interfaceIBinaryTree<outT>
{
intHeight
{
get;
}
TValue
{
get;
}
IBinaryTree<T>Left
{
get;
}
IBinaryTree<T>Right
{
get;
}
boolIsEmpty
{
get;
}
intCount
{
get;
}
}
接口很清楚,定义了一个二叉树,但是这棵二叉树的具体特性但从接口上还无从得知。现在我们再看Node类。ImmutableList<T>的EmptySingleton就是返回的上图中最上面的Node类的EmptyNode。EmptyNode定义如下:
internalstaticreadonlyNodeEmptyNode=newNode();
Node类的Key和Value属性是同一个值,就是当前节点的值。在代码中都是以Key为操作对象。下面分析Node的相关行为的时候,会有更清楚的认识。frozen是一个bool类型的变量,表示是否冻结。冻结可以说是不可变集合的一个关键特性,下面也会对此做详细的分析。
height是以当前节点为根的树的高度。
this.height=1+Math.Max(left.height,right.height);
count以当前节点为根的树的节点个数。this.count=1+left.count+right.count;
IsEmpty判断是否有子节点。publicboolIsEmpty
{
get
{
returnthis.left==null;
}
}
right和left就是左右子树。2.3行为
2.3.1初始化
我们通过下面的代码来观察Node的初始化过程。staticvoidMain(string[]args)
{
varfruitBasket=ImmutableList.Create<string>();
varass=fruitBasket.Add("ddd");
}
启动程序,首先进入ImmutableList.Create<string>()方法。Create方法直接返回ImmutableList<T>.Empty,Empty属性直接返回EmptySingleton。
调用EmptySingleton时触发ImmutableList<T>的初始化。
接下来在构造函数中调用Node.EmptyNode。
在Node类的无参构造函数中只初始化了一个变量:
此时Node.EmptyNode实例的各字段值如下图所示:
到此为止第一次初始化结束。
现在测试下带比较器的构造方式,先新建一个TestCompare类:
classTestCompare<T>:IEqualityComparer<T>
{
publicboolEquals(Tx,Ty)
{
returnx.Equals(y);
}
publicintGetHashCode(Tobj)
{
returnthis.GetHashCode();
}
}
然后更改Main函数中的代码:staticvoidMain(string[]args)
{
varfruitBasket=ImmutableList.Create<string>(newTestCompare<string>());
varass=fruitBasket.Add("ddd");
}
ImmutableList静态方法仍然在ImmutableList<T>.Empty基础上调用了WithCompare方法。WithCompare方法在初始化了valueCompare字段之后调用了构造函数ImmutableList(ImmutableList<T>.Noderoot,IEqualityComparer<T>valueComparer):
privateImmutableList(ImmutableList<T>.Noderoot,IEqualityComparer<T>valueComparer)
{
Requires.NotNull<ImmutableList<T>.Node>(root,"root");
Requires.NotNull<IEqualityComparer<T>>(valueComparer,"valueComparer");
root.Freeze();
this.root=root;
this.valueComparer=valueComparer;
}
上面的构造函数,调用了Freeze()方法,internalvoidFreeze()
{
if(!this.frozen)
{
this.left.Freeze();
this.right.Freeze();
this.frozen=true;
}
}
这段代码,实际上是一个递归调用,设置每个节点为冻结状态。带初始值的构造函数,实际是调用了Add方法,我将在下一篇博文中单独分析。
本篇博文到此结束,未完,待续。。。。。。
相关文章推荐
- Immutable Collections(3)Immutable List实现原理(中)变化中的不变
- 粗谈C#里 dictionary,HashTable,List<T>,Array 的性能优缺和实现原理。
- Immutable Collections(3)Immutable List实现原理(中)变化中的不变
- ios XML,JSON,数组解析并转换成NSMutableArray(List<class>)
- Java实现List<Map<String, Object>> 转Map<Object, Object>
- C#基础教程之IComparable用法,实现List<T>.sort()排序
- Volley<二> 实现原理深度解析
- <基础原理进阶>机器学习算法python实现【2】--ForwardPass&BackPropagation
- 自己动手,实现一种类似List<T>的数据结构(二)
- php+js+mysql设计的仿webQQ-<5>IM窗体的实现
- Java实现List<Object>转List<实体类>
- Mybatis 之List<?>传参的注意事项和原理
- List<> 转换为Dataset的C#代码实现 解决Nullable问题
- session + List<T> 实现购物车(asp.net mvc)
- List<?> list= new ArrayList<?>为什么这样写 接口引用指向实现类的对象
- spring mvc:实现给Controller函数传入list<pojo>参数
- Java实现从IP和端口列表List<String>获取分离的IP和端口值
- 黑马程序员:Java基础总结----子接口 List<E>及其实现类
- php+js+mysql设计的仿webQQ-<5>IM窗体的实现
- 探究 List<T> 集合的Where方法是如何实现的