• Immutable Collections(2)ImmutableList<T>实现原理.(上)


    Immutable Collections2ImmutableList<T>实现原理.(上)

    /玄魂

    前言

    在上一篇文章(Immutable Collections1,我简要说明了不可变集合的基本概念和简单应用。从本篇博文开始,会探讨下几个典型集合类型的内部实现机制。本篇博客主要探讨ImmutableList<T>实现原理。

    博文中引用的代码并非是.NET源码,而是反编译得来,不正确之处,还望指教。

    2.1 概述

    下图是ImmutableList<T>类型包含的核心字段、属性(并非全部),以及和其他类型的关系。这张图是自动生成的,我直接拿过来没有做什么改动,可能会让人云里雾里,下面我做简要的说明。

    处于最顶端的ImmutableList静态类,是ImmutableList<T>类型的构造者,它或者直接返回ImmutableList<T>Empty属性,或者在Empty的基础上构造ImmutableList<T>实例,比如下面的代码:

    public static ImmutableList<T> Create<T>()

                 {

                        return ImmutableList<T>.Empty;

                 }

                 public static ImmutableList<T> Create<T>(IEqualityComparer<T> equalityComparer)

                 {

                 return ImmutableList<T>.Empty.WithComparer(equalityComparer);

                 }

                 public static ImmutableList<T> Create<T>(T item)

                 {

                        return ImmutableList<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>定义如下:

    public interface IImmutableList<T> : IReadOnlyList<T>, IReadOnlyCollection<T>, IEnumerable<T>, IEnumerable

          {

                 IEqualityComparer<T> ValueComparer

                 {

                        get;

                 }

                 IImmutableList<T> Clear();

                 bool Contains(T value);

                 int IndexOf(T value);

                 IImmutableList<T> Add(T value);

                 IImmutableList<T> AddRange(IEnumerable<T> items);

                 IImmutableList<T> Insert(int index, T element);

                 IImmutableList<T> InsertRange(int index, IEnumerable<T> items);

                 IImmutableList<T> Remove(T value);

                 IImmutableList<T> RemoveAll(Predicate<T> match);

                 IImmutableList<T> RemoveRange(IEnumerable<T> items);

                 IImmutableList<T> RemoveRange(int index, int count);

                 IImmutableList<T> RemoveAt(int index);

                 IImmutableList<T> SetItem(int index, T value);

                 IImmutableList<T> Replace(T oldValue, T newValue);

                 IImmutableList<T> WithComparer(IEqualityComparer<T> equalityComparer);

          }

    IImmutableListQueries<T>定义如下:

          internal interface IImmutableListQueries<T>

          {

                 int Count

                 {

                        get;

                 }

                 ImmutableList<TOutput> ConvertAll<TOutput>(Func<T, TOutput> converter);

                 void ForEach(Action<T> action);

                 ImmutableList<T> GetRange(int index, int count);

                 void CopyTo(T[] array);

                 void CopyTo(T[] array, int arrayIndex);

                 void CopyTo(int index, T[] array, int arrayIndex, int count);

                 bool Exists(Predicate<T> match);

                 T Find(Predicate<T> match);

                 ImmutableList<T> FindAll(Predicate<T> match);

                 int FindIndex(Predicate<T> match);

                 int FindIndex(int startIndex, Predicate<T> match);

                 int FindIndex(int startIndex, int count, Predicate<T> match);

                 T FindLast(Predicate<T> match);

                 int FindLastIndex(Predicate<T> match);

                 int FindLastIndex(int startIndex, Predicate<T> match);

                 int FindLastIndex(int startIndex, int count, Predicate<T> match);

                 int IndexOf(T item);

                 int IndexOf(T item, int index);

                 int IndexOf(T item, int index, int count);

                 int LastIndexOf(T item);

                 int LastIndexOf(T item, int index);

                 int LastIndexOf(T item, int index, int count);

                 bool TrueForAll(Predicate<T> match);

          }

    其他接口,是.NET中原有接口,这里就不列举了。IImmutableList<T> 的核心行为都定义在这两个接口当中。

    SyncRootObject类型字段,作为同步锁对象。

    Empty直接返回当前集合的单例对象EmptySingleton

    ImmutableList<T>构造函数如下:

    internal ImmutableList()

                 {

                        this.root = ImmutableList<T>.Node.EmptyNode;

                        this.valueComparer = EqualityComparer<T>.Default;

                 }

                 private ImmutableList(ImmutableList<T>.Node root, IEqualityComparer<T> valueComparer)

                 {

                        root.Freeze();

                        this.root = root;

                        this.valueComparer = valueComparer;

                 }

    在构造函数中我们又发现两个很重要的类型,NodeIEqualityComparerIEqualityComparer这里就不解释了,我们重点关注Node,从字面上理解,这是一个表示节点的类,事实上它是ImmutableList<T>的核心,数据的承载和操作都是对Node类的包装。下面我们来看看Node的庐山真面目。

    2.2 Node

    Node类继承自三个接口,

    internal sealed class Node : IBinaryTree<T>, IEnumerable<T>, IEnumerable

    我们主要关注IBinaryTree<T>,定义如下:

    interface IBinaryTree<out T>

          {

                 int Height

                 {

                        get;

                 }

                 T Value

                 {

                        get;

                 }

                 IBinaryTree<T> Left

                 {

                        get;

                 }

                 IBinaryTree<T> Right

                 {

                        get;

                 }

                 bool IsEmpty

                 {

                        get;

                 }

                 int Count

                 {

                        get;

                 }

          }

    接口很清楚,定义了一个二叉树,但是这棵二叉树的具体特性但从接口上还无从得知。现在我们再看Node类。

    ImmutableList<T>EmptySingleton就是返回的上图中最上面的Node类的EmptyNodeEmptyNode定义如下:

          internal static readonly Node EmptyNode = new  Node();

    Node类的KeyValue属性是同一个值,就是当前节点的值。在代码中都是以Key为操作对象。下面分析Node的相关行为的时候,会有更清楚的认识。

    frozen是一个bool类型的变量,表示是否冻结。冻结可以说是不可变集合的一个关键特性,下面也会对此做详细的分析。

    height是以当前节点为根的树的高度。

          this.height = 1 + Math.Max(left.height, right.height);

    count以当前节点为根的树的节点个数。

    this.count = 1 + left.count + right.count;

    IsEmpty判断是否有子节点。

    public bool IsEmpty

                        {

                               get

                               {

                                      return this.left == null;

                               }

                        }

    rightleft就是左右子树。

    2.3 行为

    2.3.1    初始化

    我们通过下面的代码来观察Node的初始化过程。

      static void Main(string[] args)

            {

     

                var fruitBasket = ImmutableList.Create<string>();

              var ass  = fruitBasket.Add("ddd");

            }

    启动程序,首先进入ImmutableList.Create<string>()方法。

    Create方法直接返回ImmutableList<T>.EmptyEmpty属性直接返回EmptySingleton

    调用EmptySingleton时触发ImmutableList<T>的初始化

    接下来在构造函数中调用Node.EmptyNode

    Node类的无参构造函数中只初始化了一个变量:

    此时Node.EmptyNode实例的各字段值如下图所示:

    到此为止第一次初始化结束。

    现在测试下带比较器的构造方式,先新建一个TestCompare类:

    class TestCompare<T> : IEqualityComparer<T>

        {

            public bool Equals(T x, T y)

            {

                return x.Equals(y);

            }

            public int GetHashCode(T obj)

            {

                return this.GetHashCode();

            }

        }

    然后更改Main函数中的代码:

       static void Main(string[] args)

            {

        var fruitBasket = ImmutableList.Create<string>(new TestCompare<string>());

              var ass  = fruitBasket.Add("ddd");

            }

    ImmutableList静态方法仍然在ImmutableList<T>.Empty基础上调用了WithCompare方法。

     
    WithCompare方法在初始化了valueCompare字段之后调用了构造函数ImmutableList(ImmutableList<T>.Node root, IEqualityComparer<T> valueComparer)

          private ImmutableList(ImmutableList<T>.Node root, 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()方法,

    internal void Freeze()

                        {

                               if (!this.frozen)

                               {

                                      this.left.Freeze();

                                      this.right.Freeze();

                                      this.frozen = true;

                               }

                        }

    这段代码,实际上是一个递归调用,设置每个节点为冻结状态。

    带初始值的构造函数,实际是调用了Add方法,我将在下一篇博文中单独分析。

    本篇博文到此结束,未完,待续。。。。。。


    作者:玄魂
    出处:http://www.cnblogs.com/xuanhun/
    原文链接:http://www.cnblogs.com/xuanhun/ 更多内容,请访问我的个人站点 对编程,安全感兴趣的,加qq群:hacking-1群:303242737,hacking-2群:147098303,nw.js,electron交流群 313717550。
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
    关注我:关注玄魂的微信公众号

  • 相关阅读:
    Android ActionBar应用实战,高仿微信主界面的设计
    Android ActionBar完全解析,使用官方推荐的最佳导航栏(下) .
    Android ActionBar完全解析,使用官方推荐的最佳导航栏(上)
    actionBar兼容2.1及以上版本的做法 .
    Android UI开发详解之ActionBar .
    Android ActionBar详解(三):ActionBar实现切换Tabs标签
    Android ActionBar详解(二):ActionBar实现Tabs标签以及下拉导航 .
    完毕port(CompletionPort)具体解释
    Java的递归算法
    shell语法简单介绍
  • 原文地址:https://www.cnblogs.com/xuanhun/p/3063787.html
Copyright © 2020-2023  润新知