C#编程(三十五)----------foreach和yield
枚举
在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];
}
}
}
}
C#编程(三十五)----------foreach和yield的更多相关文章
- centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件、目录属性 shell数组简单用法 $( ) 和${ } 和$(( )) 与 sh -n sh -x sh -v 第三十五节课
centos shell脚本编程1 正则 shell脚本结构 read命令 date命令的用法 shell中的逻辑判断 if 判断文件.目录属性 shell数组简单用法 $( ) 和$ ...
- NeHe OpenGL教程 第三十五课:播放AVI
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- JAVA之旅(三十五)——完结篇,终于把JAVA写完了,真感概呐!
JAVA之旅(三十五)--完结篇,终于把JAVA写完了,真感概呐! 这篇博文只是用来水经验的,写这个系列是因为我自己的java本身也不是特别好,所以重温了一下,但是手比较痒于是就写出了这三十多篇博客了 ...
- 第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码
第三百三十五节,web爬虫讲解2—Scrapy框架爬虫—豆瓣登录与利用打码接口实现自动识别验证码 打码接口文件 # -*- coding: cp936 -*- import sys import os ...
- 孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容
孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.打开文件后,要务必记得关闭,所以一般的写法应当 ...
- 剑指Offer(三十五):数组中的逆序对
剑指Offer(三十五):数组中的逆序对 搜索微信公众号:'AI-ming3526'或者'计算机视觉这件小事' 获取更多算法.机器学习干货 csdn:https://blog.csdn.net/bai ...
- Java进阶(三十五)java int与integer的区别
Java进阶(三十五)java int与Integer的区别 前言 int与Integer的区别从大的方面来说就是基本数据类型与其包装类的区别: int 是基本类型,直接存数值,而Integer是对象 ...
- Gradle 1.12用户指南翻译——第三十五章. Sonar 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- SQL注入之Sqli-labs系列第三十四关(基于宽字符逃逸POST注入)和三十五关
开始挑战第三十四关和第三十五关(Bypass add addslashes) 0x1查看源码 本关是post型的注入漏洞,同样的也是将post过来的内容进行了 ' \ 的处理. if(isset($_ ...
- “全栈2019”Java多线程第三十五章:如何获取线程被等待的时间?
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
随机推荐
- jenkins执行构建任务报错之java.lang.NoSuchFieldError: DEFAULT_USER_SETTINGS_FILE
在执行创建工作空间时候,创建不成功,出现错误?? ......... java.lang.NoSuchFieldError: DEFAULT_USER_SETTINGS_FILE ......... ...
- spring-dao.xml 模板
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.sp ...
- java 捕获所有异常
1.) 通过捕获异常类型的基类Exception就可以处理所有类型的异常.(事实上还有其它的基类,但Exception是同编程活动相关的基类) 2.)因为Exception是与编程有关的所有异常类的基 ...
- Java第三阶段学习(十二、HttpServletRequest与HttpServletResponse)
一.HttpServletRequest 1.概述: 我们在创建Servlet时会覆盖service()方法,或doGet()/doPost(),这些方法都有两个参数,一个为代表请求的request和 ...
- 【LOJ】#2533. 「CQOI2018」交错序列
题解 有毒吧 这题\(O(n)\)过不去 非得写\(O((a + b)^3\log n)\)的矩乘,同样很卡常 把\(x\)换成\(n - y\) 我们拆完式子发现是这样的 \(\sum_{i = 0 ...
- python 包详解
包 包是一种管理 Python 模块命名空间的形式,采用"点模块名称". 比如一个模块的名称是 A.B, 那么他表示一个包 A中的子模块 B . 就好像使用模块的时候,你不用担心不 ...
- 000 Jquery的Hello World程序
1.介绍Jquery 2.简介 3.新建一个静态项目,并粘贴jquery库 4.程序 <!DOCTYPE html> <html> <head> <meta ...
- # Java反射2——获取实体所有属性和方法,并对属性赋值
1.一个普通的实体Person: private int id; private String name; private Date createdTime; ... //其它字段 // get se ...
- Noip2018游记——AFO
本来Day 0和Day 1写得挺轻松的,结果没想到Day 2是这样的画风...心情逐渐沉重... Day 0 白天的时候颓的一批,上午考的信心赛还打错了一个字母然后$100pts\rightarrow ...
- app微信支付宝支付后台的插件模式+回调通过spring广播处理后续业务(已亲测可用)
写在前面的话:每当我们做一个项目,基本上都会涉及到支付的业务,最常用的莫过于微信和支付宝的支付了,项目有bug,有问题,都不叫问题,可一旦钱出了问题,那就是大问题了,所以在支付业务上我们必须慎之又慎! ...