zoukankan      html  css  js  c++  java
  • [c#基础]集合foreach的必要条件和自定义集合

    引言

    最近翻看了之前的学习笔记,看到foreach,记得当时老师讲的时候,有点犯浑,不是很明白,这好比,上小学时,你不会乘法口诀,但是随着时间的增长,你不自觉的都会了,也悟出个小道理,有些东西,你当时不太懂,但随着你的阅历和经验的增长,有那么一天你会恍然大悟,哦,原来是这样。

    自定义集合类

    提到foreach就不得不说集合,那么就先从自定义的集合开始吧。

     1 using System;
     2 using System.Collections.Generic;
     3 using System.Linq;
     4 using System.Text;
     5 using System.Threading.Tasks;
     6 
     7 namespace Wolfy.自定义集合
     8 {
     9     /// <summary>
    10     /// 自定义集合类
    11     /// </summary>
    12     public class MyArrayList
    13     {
    14         /// <summary>
    15         /// 集合的容量属性 成倍数增加0,4,8,且只读
    16         /// </summary>
    17         public int Capacity
    18         {
    19             get
    20             {
    21                 return this.objArray.Length == 0 ? 0 : this.index > this.objArray.Length ? this.objArray.Length * 2 : this.objArray.Length;
    22             }
    23         }
    24         /// <summary>
    25         /// 集合实际元素个数 且只读
    26         /// </summary>
    27         public int Count
    28         {
    29             get
    30             {
    31                 return this.index;
    32             }
    33         }
    34         private int index;
    35         private object[] objArray;
    36         public MyArrayList()
    37         {
    38             index = 0;
    39             //初始化0长度的数组
    40             this.objArray = new object[0];
    41         }
    42         /// <summary>
    43         /// 添加元素
    44         /// </summary>
    45         /// <param name="value">元素值</param>
    46         public void Add(object value)
    47         {
    48             if (index >= this.objArray.Length)
    49             {
    50                 object[] newArray = index == 0 ? new object[this.objArray.Length + 4] : new object[this.objArray.Length * 2];
    51                 objArray.CopyTo(newArray, 0);
    52                 objArray = newArray;
    53                 objArray[index++] = value;
    54             }
    55             else
    56             {
    57                 objArray[index++] = value;
    58             }
    59         }
    60         /// <summary>
    61         /// 添加数组
    62         /// </summary>
    63         /// <param name="objs"></param>
    64         public void AddRange(object[] objs)
    65         {
    66             for (int i = 0; i < objs.Length; i++)
    67             {
    68                 this.Add(objs[i]);
    69             }
    70         }
    71     }
    72 }

    不知道自定义的集合和ArrayList是否一样,可以简单的测试一下。

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Wolfy.自定义集合
     9 {
    10     class Program
    11     {
    12         static void Main(string[] args)
    13         {
    14             ArrayList list = new ArrayList();
    15             //MyArrayList list = new MyArrayList();
    16             Console.WriteLine("count:" + list.Count);
    17             Console.WriteLine("Capacity:" + list.Capacity);
    18             list.Add(1);
    19             list.Add(1);
    20             Console.WriteLine("count:" + list.Count);
    21             Console.WriteLine("Capacity:" + list.Capacity);
    22             list.Add(1);
    23             list.Add(1);
    24             list.Add(1);
    25             Console.WriteLine("count:" + list.Count);
    26             Console.WriteLine("Capacity:" + list.Capacity);
    27             list.Add(1);
    28             list.Add(1);
    29             list.Add(1);
    30             list.Add(1);
    31             list.Add(1);
    32             list.Add(1);
    33             Console.WriteLine("count:" + list.Count);
    34             Console.WriteLine("Capacity:" + list.Capacity);
    35             object[] arr = { 1, 2, 3, 4, 5, 6 };
    36             list.AddRange(arr);
    37             Console.WriteLine("count:" + list.Count);
    38             Console.WriteLine("Capacity:" + list.Capacity);
    39             Console.Read();
    40         }
    41     }
    42 }

    此时是.Net中的ArrayList,结果:

    自定义的集合,结果:

    输出结果一样,那么现在用foreach遍历,自定义集合中的元素。F6编译,会提示错误。

    foreach语句

     其实foreach是怎样工作的呢?

    众所周知foreach中in后面的对象应该是实现IEnumerable接口的,程序运行时本质是在调用IEnumerable的GetEnumerator函数来返回一个IEnumerator对象,foreach就是利用IEnumerator对象的Current,MoveNext和Reset成员来进行一段数据的枚举。简单的代码实现如下:

    1             //System.Collections下的IEnumerator
    2             IEnumerator enumerator = this.objArray.GetEnumerator();
    3             while (enumerator.MoveNext())
    4             {
    5                 Console.WriteLine(enumerator.Current);
    6             }

    将这个代码放在自定义集合中,定义一个方法GetArray(),然后测试一下

     1         /// <summary>
     2         /// 得到所有的元素
     3         /// </summary>
     4         public void GetArray()
     5         {
     6             //System.Collections下的IEnumerator
     7             IEnumerator enumerator = this.objArray.GetEnumerator();
     8             while (enumerator.MoveNext())
     9             {
    10                 Console.Write(enumerator.Current+“,”);
    11             }
    12         }

    测试结果:

    你运行会发现多出很多逗号,原因是执行后,enumerator没有被Dispose掉,而继承IDisposable的迭代器(IEnumerator)在foreach结束后会被正确处理掉(调用Dispose方法)。

    自定义集合实现IEnumerable接口

    实现IEnumerable接口必须实现它里面的成员GetEnumerator()方法:

    1         public IEnumerator GetEnumerator()
    2         {
    3             throw new NotImplementedException();
    4         }

    该方法的返回值为实现了IEnumerator接口的类的对象。那么现在需要定义一个实现了该接口的类。

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Wolfy.自定义集合
     9 {
    10     public class MyEnumerator : IEnumerator
    11     {
    12         /// <summary>
    13         /// 返回当前指针指向的元素的值
    14         /// </summary>
    15         public object Current
    16         {
    17             get { throw new NotImplementedException(); }
    18         }
    19         /// <summary>
    20         /// 将指针向前移动1位,并判断当前位有没有元素.指针默认在-1位置
    21         /// </summary>
    22         /// <returns></returns>
    23         public bool MoveNext()
    24         {
    25             throw new NotImplementedException();
    26         }
    27         /// <summary>
    28         /// 重置
    29         /// </summary>
    30         public void Reset()
    31         {
    32             throw new NotImplementedException();
    33         }
    34     }
    35 }

    迭代需要数组参数,在构造函数中将自定义集合中的数组传进来,并且在MoveNext中需要判断指针是否移动到数组的末尾,那么需要数组的长度。
    MyArrayList中GetEnumerator()方法实现

    1         public IEnumerator GetEnumerator()
    2         {
    3             return new MyEnumerator(this.objArray, this.Count);
    4         }

    MyEnumerator类

     1 using System;
     2 using System.Collections;
     3 using System.Collections.Generic;
     4 using System.Linq;
     5 using System.Text;
     6 using System.Threading.Tasks;
     7 
     8 namespace Wolfy.自定义集合
     9 {
    10     public class MyEnumerator : IEnumerator
    11     {
    12         /// <summary>
    13         /// 指针的默认位置
    14         /// </summary>
    15         private int index = -1;
    16         private object[] objArray;
    17         /// <summary>
    18         /// 数组长度
    19         /// </summary>
    20         private int count;
    21         public MyEnumerator(object[] objArray, int count)
    22         {
    23 
    24             this.objArray = objArray;
    25             this.count = count;
    26         }
    27         /// <summary>
    28         /// 返回当前指针指向的元素的值
    29         /// </summary>
    30         public object Current
    31         {
    32             get { return this.objArray[index]; }
    33         }
    34         /// <summary>
    35         /// 将指针向前移动1位,并判断当前位有没有元素.指针默认在-1位置
    36         /// </summary>
    37         /// <returns></returns>
    38         public bool MoveNext()
    39         {
    40             index++;//指针首先向前移动一位
    41             if (index < this.count)
    42             {
    43                 return true;
    44             }
    45             else
    46             {
    47                 return false;
    48             }
    49         }
    50         /// <summary>
    51         /// 重置
    52         /// </summary>
    53         public void Reset()
    54         {
    55             index = -1;
    56         }
    57     }
    58 }

    测试,foreach语句,然后编译不再报错,说明已经成功了,结果如下:

    这次后边不会多出逗号,原因实现了迭代器接口而迭代器继承自IDisposable接口,最后调用了Dispose()方法

    代码下载,请戳这里:http://pan.baidu.com/s/1pJsGyHt

    总结

    foreach遍历in后面的对象需实现IEnumerable接口。

    迭代器概念可参考:http://msdn.microsoft.com/zh-cn/library/dscyy5s0(VS.80).aspx

    东西比较基础,以上是个人理解,如理解有误,请指正,以免误人子弟。

  • 相关阅读:
    js动态获取地址栏后的参数
    html页面保存数的两种方式
    微信开发之八 页面获取周围beacon设备
    【摄影】田子坊
    最好的时光在路上,最美的风景在远方
    【前端统计图】echarts实现简单柱状图
    js实现计时功能
    luogu 电车
    cogs luogu 砍树
    cogs 通往奥格瑞玛的道路 WD
  • 原文地址:https://www.cnblogs.com/wolf-sun/p/3549968.html
Copyright © 2011-2022 走看看