zoukankan      html  css  js  c++  java
  • 模仿.NET框架ArrayList写一个自己的动态数组类MyArrayList,揭示foreach实现原理

    通过.NET反编译工具可以查看到ArrayList内部的代码,发现ArrayList并非由链表实现,而是由一个不断扩容的数组对象组成。

    下面模仿ArrayList写一个自己的MyArrayList。

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Collections;

    namespace 模仿动态数组

    {

             /// <summary>

             /// 模拟ArrayList类

             /// </summary>

             class MyArrayList

             {

                       /// <summary>

                       /// 初始化MyArraiList的新实例,用默认的初始值初始化动态数组

                       /// </summary>

                       public MyArrayList()

                       {

                                //将容量属性初始值设为0

                                Capacity = 0;

                                //实例化一个新的数组实例

                                arr = new object[Capacity];

                                //定义数组索引为0

                                Index = 0;

                       }

                       /// <summary>

                       /// 初始化MyArrayList, 用指针的容量初始化动态数组,如果参数小于0,则抛出异常

                       /// </summary>

                       /// <param name="capacity">指定要初始化动态数组的大小</param>

                       public MyArrayList(int capacity)

                       {

                                //判断传入的容量是否合法

                                if (capacity < 0)

                                {

                                         //如果参数不合法,抛出异常

                                         throw new ArgumentOutOfRangeException("capacity", "capacity must not less than zero!");

                                }

                      

                                //如果参数合法,用指定的大小初始化数组

                                this.arr = new object[capacity];

                       }

                       /// <summary>

                       /// 成员属性:数组引用

                       /// </summary>

                       private object[] arr;

                       /// <summary>

                       /// 成员属性:数组当前指针

                       /// </summary>

                       public int Index { get; set; }

                       /// <summary>

                       /// 成员属性:数组容量

                       /// </summary>

                       public int Capacity { get; set; }

                       /// <summary>

                       /// 构造一个索引器

                       /// </summary>

                       /// <param name="index">指定的索引值</param>

                       /// <returns>返回当前索引下数组的值</returns>

                       public object this[int index]

                       {

                                get

                                {

                                         return arr[index];

                                }

                                set

                                {

                                         //判断参数是否合法

                                         if (index < 0 || index >= Index)

                                         {

                                                   //如果不合法,抛出异常

                                                   throw new ArgumentOutOfRangeException("index", "index must be not less than 0 and not biger than index");

                                         }

                                         //否则,赋值

                                         arr[index] = value;

                                }

                       }

                       /// <summary>

                       /// 成员方法:添加元素

                       /// </summary>

                       /// <param name="value"></param>

                       public void Add(object value)

                       {

                                //判断当前索引是否小于数组长度

                                if (Index < arr.Length)

                                {

                                         //如果小于数组长度,则添加

                                         arr[Index++] = value;

                                }

                                else

                                {

                                         //如果超出数组长度-1

                                         Capacity = arr.Length * 2;

                                         //创建一个比当前数组大两倍的数组

                                         object[] newArr = new object[arr.Length*2];

                                         //将就数组的数据拷贝到新数组中

                                         Array.Copy(arr, newArr,arr.Length);

                                         //就数组的引用指向新的数组

                                         arr = newArr;

                                         //添加元素

                                         arr[Index++] = value;

                                }

                       }

             }

    }

    MyArrayList list = new MyArrayList();

    //往动态数组中添加对象

    For (int I = 0; I < 10; i++)

    {

             List.Add(i);

    }

    //遍历

    foreach (object val in list)

    {

             Console.WriteLine(val);

    }

    发现这里出错了,为什么.Net Framework里的ArrayList对象可以用foreach遍历,而我们自己写的却不行

    通过CSDN的介绍可知,

    Foreach()等同于如下代码

    IEnumerator  tor = new list. GetEnumerator();

    While (list.MoveNext())

    {

             Console.WriteLine(list.Current);

    }

    foreach内部实际上调用对象内部的GetEnumerator()方法将动态数组封装成迭代器

    GetEnumerator()也就是工厂函数,通过传入的arr和count生成迭代器对象

    而GetEnumerator()来自于 IEnumerable接口。因此要想让foreach遍历自己写的动态数组类,必须实现IEnumerable接口。

    该接口中的GetEnumerator要求返回一个对象,而且返回的是对象的父类,所以必须写一个迭代器对象的类,并且实现了IEnumerator,这样就可以在外部通过IEnumerator类型的变量调用它指向它的子类中实现了的方法。

    基于此,我们来实现这个接口,代码如下:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Collections;

    namespace 模仿动态数组

    {

             /// <summary>

             /// 模拟ArrayList类

             /// </summary>

             class MyArrayList:IEnumerable

             {

                       /// <summary>

                       /// 初始化MyArraiList的新实例,用默认的初始值初始化动态数组

                       /// </summary>

                       public MyArrayList()

                       {

                                //将容量属性初始值设为0

                                Capacity = 0;

                                //实例化一个新的数组实例

                                arr = new object[Capacity];

                                //定义数组索引为0

                                Index = 0;

                       }

                       /// <summary>

                       /// 初始化MyArrayList, 用指针的容量初始化动态数组,如果参数小于0,则抛出异常

                       /// </summary>

                       /// <param name="capacity">指定要初始化动态数组的大小</param>

                       public MyArrayList(int capacity)

                       {

                                //判断传入的容量是否合法

                                if (capacity < 0)

                                {

                                         //如果参数不合法,抛出异常

                                         throw new ArgumentOutOfRangeException("capacity", "capacity must not less than zero!");

                                }

                      

                                //如果参数合法,用指定的大小初始化数组

                                this.arr = new object[capacity];

                       }

                       /// <summary>

                       /// 成员属性:数组引用

                       /// </summary>

                       private object[] arr;

                       /// <summary>

                       /// 成员属性:数组当前指针

                       /// </summary>

                       public int Index { get; set; }

                       /// <summary>

                       /// 成员属性:数组容量

                       /// </summary>

                       public int Capacity { get; set; }

                       /// <summary>

                       /// 构造一个索引器

                       /// </summary>

                       /// <param name="index">指定的索引值</param>

                       /// <returns>返回当前索引下数组的值</returns>

                       public object this[int index]

                       {

                                get

                                {

                                         return arr[index];

                                }

                                set

                                {

                                         //判断参数是否合法

                                         if (index < 0 || index >= Index)

                                         {

                                                   //如果不合法,抛出异常

                                                   throw new ArgumentOutOfRangeException("index", "index must be not less than 0 and not biger than index");

                                         }

                                         //否则,赋值

                                         arr[index] = value;

                                }

                       }

                       /// <summary>

                       /// 成员方法:添加元素

                       /// </summary>

                       /// <param name="value"></param>

                       public void Add(object value)

                       {

                                //判断当前索引是否小于数组长度

                                if (Index < arr.Length)

                                {

                                         //如果小于数组长度,则添加

                                         arr[Index++] = value;

                                }

                                else

                                {

                                         //如果超出数组长度-1

                                         Capacity = arr.Length * 2;

                                         //创建一个比当前数组大两倍的数组

                                         object[] newArr = new object[arr.Length*2];

                                         //将就数组的数据拷贝到新数组中

                                         Array.Copy(arr, newArr,arr.Length);

                                         //就数组的引用指向新的数组

                                         arr = newArr;

                                         //添加元素

                                         arr[Index++] = value;

                                }

                       }

                       /// <summary>

                       /// 返回一个迭代器对象

                       /// </summary>

                       /// <returns>返回一个迭代器对象</returns>

                       public IEnumerator GetEnumerator()

                       {

                               

                                return new MyIEnumerator(arr, Index);

                       }

             }

    }

    接着完成 迭代器对象的类

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using System.Collections;

    namespace 模仿动态数组

    {

             /// <summary>

             /// 一个迭代器的类,用来处理实现了ICollection接口的数组类

             /// </summary>

             class MyIEnumerator:IEnumerator

             {

                       private object[] arr;

                       private int count;

                       private int index;

                       /// <summary>

                       /// 初始化MyIEnumerator的新实例,以指定的arr和count(数组实际长度,非容量)

                       /// </summary>

                       /// <param name="arr"></param>

                       /// <param name="count"></param>

                       public MyIEnumerator(object[] arr, int count)

                       {

                                this.arr = arr;

                                this.count = count;

                                //当前指针在首位

                                this.index = -1;

                       }

                       /// <summary>

                       /// 成员属性(只读):返回当前指针指向的元素

                       /// </summary>

                       public object Current

                       {

                                get

                                {

                                         return arr[index];

                                }

                       }

                       /// <summary>

                       /// 成员方法:移动指针,判断当前指针指向的数是否合法

                       /// </summary>

                       /// <returns></returns>

                       public bool MoveNext()

                       {

                                index++;

                                return index < count;

                       }

                       /// <summary>

                       /// 成员方法:将当前数组指针重置为第一个元素之前

                       /// </summary>

                       public void Reset()

                       {

                                index = -1;

                       }

             }

    }

    好了,这时再用foreach遍历我们自己的数组,看到效果了吧。

    MyArrayList list = new MyArrayList();

    List.Add(1);

    List.Add(2);

    List.Add(3);

    List.Add(4);

    List.Add(5);

    Foreach (object val in list)

    {

             Console.WriteLine(val);

    }

    输出

    1

    2

    3

    4

    5

  • 相关阅读:
    网络中常用的各种协议(针对TCP/IP协议组)
    报错注入小技巧
    2017swpu-ctf总结
    2017EIS高校运维大赛ctf wirteup
    discuz 3.x ssrf分析
    ssrf漏洞分析
    xxe漏洞分析
    phpcms9.6 注入分析
    74cms漏洞分析
    关于npm
  • 原文地址:https://www.cnblogs.com/hoosway/p/3665078.html
Copyright © 2011-2022 走看看