枚举

在foreach语句中使用枚举,可以迭代集合中的元素,且无需知道集合中的元素个数.

数组或集合实现带GetEumerator()方法的IEumerable接口.GetEumerator()方法返回一个实现IEunmerable接口的枚举.

GetEnumerator()方法用IEnumerable接口定义.foreach语句并不真的需要在集合类中实现这个借口.有一个名为GetEnumerator()的方法,他返回实现了IEnumerator接口的对象就足够了.

IEnumerator接口

foreach语句使用IEnumerator接口的方法和属性,迭代集合中的所有元素.为此IEnumerator定义了Current属性,来返回光标所在的元素,该接口的MoveNext()方法移动到集合的下一个元素上,如果有这个元素,该方法就返回true.如果集合不再有更多的元素,该方法就返回false.

这个借口的泛型版本IEnumerator<T>派生自接口IDisposable,因此定义了Dispose()方法,来清理枚举器占用的资源.

foreach语句

C#的foreach语句不会解释为IL代码中的foreach语句.C#编译器会把foreach语句转换为IEnumerable接口的方法和属性.案例:

int[] arr = { 1, 2, 3, 4, 5, 6, 7, 8 };

foreach (var item in arr)

{

Console.WriteLine(item);

}

很明显,foreach语句很简洁,但是他的有点不仅仅在于此,它的效率也是很高的,不用考虑数组是几维的.案例:

int[,] array = new int[8, 8];

for (int i = 0; i < array.GetLength(0); i++)

{

for (int j = 0; j < array.GetLength(1); j++)

{

Console.WriteLine(array[i,j].ToString());

}

}

Console.ReadKey();

使用foreach:

foreach (int item in array)

{

Console.WriteLine(item.ToString());

}

对于三维或者更多维,foreach语句不用发生任何变化,而对于for语句就要进行修改了.

foreach完成类型转换操作,案例:

int[] array = new int[100];

ArrayList aList = new ArrayList();

aList.AddRange(array);

foreach (int item in aList)

{

Console.WriteLine(item.ToString());

}

for (int i = 0; i < aList.Count; i++)

{

int n = (int)aList[i];

Console.WriteLine(n.ToString());

}

Console.ReadKey();

foreach并没有增加资源使用,由于对于继承了IEnumerable接口的数据类型,才能使用foreach语句,那么对于使用foreach会访问IEnumerable接口中的GetEnumerator()方法来进行枚举,那么对应如上的foreach语句,对应的语句如下:

IEnumerator it = aList.GetEnumerator() as IEnumerator;

using (IDisposable disp = it as IDisposable)

{

while (it.MoveNext())

{

int elem = (int)it.Current;

Console.WriteLine(elem.ToString());

}

}

也即是说再出了foreach语句之后对于IEnumerator的对象也进行IDispose处理.

foreach的两种限制

不能修改枚举成员:

int[] array = new int[100];

foreach (var item in array)

{

item++;//这是错误的,因为枚举成员是只读的

Console.WriteLine(item.ToString());

}

不要对集合进项删除操作:

int[] array = new int[100];

ArrayList alist = new ArrayList();

alist.AddRange(array);

foreach (var item in alist)

{

alist.Remove(item);//这是错误的

Console.WriteLine(item.ToString());

}

对于删除成员和修改成员可以使用for循环来处理,对于一个记录集的多条数据删除问题,也是经常出现的问题,由于在一些记录集中进行删除的时候,在删除操作之后相应的索引也发生了变化,这时候的删除要反过来进行删除:

int[] array = new int[100];

ArrayList alist = new ArrayList();

alist.AddRange(array);

for (int i = alist.Count-1; i >=0; i--)

{

int n = (int)alist[i];

if (n==5)

{

alist.RemoveAt(i);

}

Console.WriteLine(n.ToString());

}

除了上述提到的foreach的两个约束外,foreach可以用于人和循环.

yield语句

C#中的yield语句便于创建枚举器.

yield语句的两种形式:

1.yield return <expression>

2.yield break;

使用一个yield return语句返回集合的一个元素

包含yield语句的方法或属性是迭代器.迭代器必须满足下列要求:

a.返回类型必须是IEnumerable,IEnumerable<T>,IEnumerator或IEnumerator<T>

b.他不能有任何ref或out参数.

yield return语句不能位于try-catch块;yield return语句可以位于try-finally的try中

yield return语句返回集合的一个元素,并移动到下一个元素上.yield break可以停止迭代.

class Program

{

static void Main(string[] args)

{

HelloCollection hello = new HelloCollection();

foreach(string item in hello)

{

Console.WriteLine(item);

}

Console.ReadKey();

}

}

public class HelloCollection

{

public  IEnumerator<string> GetEnumerator()

{

//yield return语句返回集合的一个元素,并移动到下一个元素上

//yield break可以终止迭代

yield return "hello";

yield return "world";

}

}

使用yield return语句实现以不同方式迭代集合的类:

using System;

using System.Collections;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace 枚举

{

class Program

{

static void Main(string[] args)

{

MusicTitles music = new MusicTitles();

foreach(var item in music.GetEnumerator())

{

Console.WriteLine(item);

}

Console.WriteLine();

foreach (string item in music.Reverse())

{

Console.WriteLine(item);

}

Console.WriteLine();

foreach (var item in music.Subset(2,2))

{

Console.WriteLine(item);

}

Console.ReadKey();

}

}

public class MusicTitles

{

string[] names = {"a","b","c","d" };

public IEnumerable<string> GetEnumerator()

{

foreach (string item in names)

{

yield return item;

}

}

public IEnumerable<string> Reverse()

{

for (int i = 3; i >=0; i--)

{

yield return names[i];

}

}

public IEnumerable<string> Subset(int index, int offert)

{

for (int i = index; i < index+offert; i++)

{

yield return names[i];

}

}

}

}

最新文章

  1. decimal与double,float的选择与区别
  2. 通过圆形载入View了解自定义View
  3. Oracle数据库like和not like使用
  4. &lt;转&gt;MFC注册系统/全局热键。
  5. 解决 window server2008 r2 没有注册Ofiice组件的方法
  6. python(6)-执行shell命令
  7. 汇编语言第二版 程序在dos中执行情况.P86-87
  8. In-Cell、On-Cell和OGS全贴合屏幕技术区别
  9. Open the Lock
  10. Mask_RCNN学习记录(matterport版本)
  11. 利用ApplicationContextAware装配Bean
  12. 【JVM】6、聊聊JVM常用参数设置
  13. 【瞎搞题】gym226123 L. For the Honest Election
  14. c# zfc
  15. DG搭建方式区分
  16. (转)MyEclipse10下创建web项目并发布到Tomcat
  17. 关于使用rem单位、css函数calc()进行自适应布局
  18. 基于html5可拖拽图片循环滚动切换
  19. CMake INSTALL 命令设置exe dll lib的安装位置
  20. codeforces 792D - Paths in a Complete Binary Tree

热门文章

  1. node.js开发web
  2. Java继承概述
  3. Java 基本语法---Java数组
  4. Coursera台大机器学习技法课程笔记08-Adaptive Boosting
  5. laravel5.3之后可以使用withCount()这个方法
  6. ****timeago.js插件:jquery实现几分钟前、几小时前、几天前等时间差显示效果的代码实例
  7. zoj 3819(2014牡丹江现场赛 A题 )
  8. #CSS margin-top父元素下落
  9. 【LOJ】#2525. 「HAOI2018」字串覆盖
  10. 【Ray Tracing The Next Week 超详解】 光线追踪2-4 Perlin noise