class Program
{
static void Main(string[] args)
{
object[] values = new object[] { "a", "b", "c", "d", "e" };
IterationSample sample = new IterationSample(values, );
foreach (var item in sample)
{
Console.WriteLine(item);
}
Console.ReadKey();
}
}
public class IterationSample : IEnumerable
{
public object[] values;
int startPoint;
public IterationSample(object[] values, int startingPoint)
{
this.values = values;
this.startPoint = startingPoint;
}
public IEnumerator GetEnumerator()
{
//return new IterationSampleIterator(this);
for (int index = ; index < values.Length; index++)
{
yield return values[(index + startPoint) % values.Length];
}
}
}
public class IterationSampleIterator : IEnumerator
{
IterationSample parent;
int position;
public IterationSampleIterator(IterationSample parent)
{
this.parent = parent;
this.position = -;
}
public object Current
{
get
{
if (position == - || position == parent.values.Length)
{
throw new InvalidOperationException();
}
int index = position + parent.values.Length;
index = index % parent.values.Length;
return parent.values[index];
}
} public bool MoveNext()
{
if (position != parent.values.Length)
{
position++;
}
return position < parent.values.Length;
} public void Reset()
{
position = -;
}
}

6.2.2 观察迭代器的工作流程

     class Program
{
static readonly string Padding = new string(' ', );
static void Main(string[] args)
{
IEnumerable<int> iterable = CreatteEnumerable(Padding);
IEnumerator<int> iterator = iterable.GetEnumerator();
Console.WriteLine("starting iterate"); while (true)
{
Console.WriteLine("=======================================");
Console.WriteLine("calling MoveNext()");
bool result = iterator.MoveNext();
Console.WriteLine("moveNext result = {0}", result);
if (!result)
break;
Console.WriteLine("fetching current");
Console.WriteLine("current result = {0}", iterator.Current);
} Console.ReadKey();
}
static IEnumerable<int> CreatteEnumerable(string Padding)
{
Console.WriteLine("{0} start of createEnumerbale padding", Padding); for (int i = ; i < ; i++)
{
Console.WriteLine("{0} about to yield {1}", Padding, i);
yield return i;
Console.WriteLine("{0} after padding", Padding);
}
Console.WriteLine("{0} yield final value ", Padding);
yield return -;
Console.WriteLine("{0} end of createEnumerable();", Padding);
}
/* starting iterate
=======================================
calling MoveNext()
start of createEnumerbale padding
about to yield 0
moveNext result = True
fetching current
current result = 0
=======================================
calling MoveNext()
after padding
about to yield 1
moveNext result = True
fetching current
current result = 1
=======================================
calling MoveNext()
after padding
about to yield 2
moveNext result = True
fetching current
current result = 2
=======================================
calling MoveNext()
after padding
yield final value
moveNext result = True
fetching current
current result = -1
=======================================
calling MoveNext()
end of createEnumerable();
moveNext result = False */
}

 6.2.3 进一步了解迭代器执行流程

1. 使用 yield break 结束迭代器的执行

     class Program
{
static void Main(string[] args)
{
DateTime stop = DateTime.Now.AddSeconds();
foreach (var item in CountWithTimeLimit(stop))
{
Console.WriteLine("received {0}", item);
Thread.Sleep();
}
Console.ReadKey();
}
static IEnumerable<int> CountWithTimeLimit(DateTime limit)
{
for (int i = ; i < ; i++)
{
if (DateTime.Now >= limit)
{
yield break;
}
yield return i;
}
}
}

2.  finally 代码块的执行

     class Program
{
static void Main(string[] args)
{
DateTime stop = DateTime.Now.AddSeconds();
foreach (var item in CountWithTimeLimit(stop))
{
Console.WriteLine("received {0}", item);
if (item > )
{
Console.WriteLine("returning");
return;
}
Thread.Sleep();
}
Console.ReadKey();
}
static IEnumerable<int> CountWithTimeLimit(DateTime limit)
{
try
{
for (int i = ; i < ; i++)
{
if (DateTime.Now >= limit)
{
yield break;
}
yield return i;
}
}
finally
{
Console.WriteLine("stopping");
Console.ReadKey();
}
}
/*
received 0
received 1
received 2
received 3
received 4
returning
stopping
*/
}

foreach 会在它自己的 finally 代码块中调用 IEnumerator 所提供的Dispose 方法(就像 using 语句)。
当迭代器完成迭代之前,你如果调用由迭代器代码块创建的迭代器上的 Dispose ,
那么状态机就会执行在代码当前“暂停”位置范围内的任何 finally 代码块。
这个解释复杂且有点详细,但结果却很容易描述:只要调用者使用了 foreach 循环,迭代器块中的 finally 将按照你期望的方式工作。

     class Program
{
static void Main(string[] args)
{
DateTime stop = DateTime.Now.AddSeconds();
IEnumerable<int> iterable = CountWithTimeLimit(stop);
IEnumerator<int> iterator = iterable.GetEnumerator(); iterator.MoveNext();
Console.WriteLine("received {0}", iterator.Current); iterator.MoveNext();
Console.WriteLine("received {0}", iterator.Current); Console.ReadKey();
}
static IEnumerable<int> CountWithTimeLimit(DateTime limit)
{
try
{
for (int i = ; i < ; i++)
{
if (DateTime.Now >= limit)
{
yield break;
}
yield return i;
}
}
finally
{
Console.WriteLine("stopping");
Console.ReadKey();
}
}
/*
received 0
received 1
*/
}

幸好,作为开发人员我们不需要太关心编译器是如何解决这些问题的。不过,关于实现中的以下一些奇特之处还是值得了解的:
 在第一次调用 MoveNext 之前, Current 属性总是返回迭代器产生类型的默认值;
 在 MoveNext 返回 false 之后, Current 属性总是返回最后的生成值;
 Reset 总是抛出异常,而不像我们手动实现的重置过程那样,为了遵循语言规范,这是必要的行为;
 嵌套类总是实现 IEnumerator 的泛型形式和非泛型形式(提供给泛型和非泛型的IEnumerable 所用)。

6.3.2 迭代文件中的行

     class Program
{
static void Main(string[] args)
{
string fileName = string.Format(@"{0}aaa.txt", AppDomain.CurrentDomain.BaseDirectory);
foreach (var item in ReadLines(fileName))
{
Console.WriteLine(item);
} Console.ReadKey();
}
static IEnumerable<string> ReadLines(string fileName)
{
using (TextReader reader = File.OpenText(fileName))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
}

 6.3.3 使用迭代器块和谓词对项进行延迟过滤

     class Program
{
static void Main(string[] args)
{
string fileName = string.Format(@"{0}aaa.txt", AppDomain.CurrentDomain.BaseDirectory); IEnumerable<string> lines = ReadLines(fileName);
Predicate<string> predicate = line => line.StartsWith("using"); foreach (var item in Where(lines, predicate))
{
Console.WriteLine(item);
} Console.ReadKey();
}
public static IEnumerable<T> Where<T>(IEnumerable<T> source, Predicate<T> predicate)
{
if (source.IsNull() || predicate.IsNull())
throw new ArgumentException(); return WhereImpl(source, predicate);
}
private static IEnumerable<T> WhereImpl<T>(IEnumerable<T> source, Predicate<T> predicate)
{
foreach (T item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
static IEnumerable<string> ReadLines(string fileName)
{
return ReadLines(() => { return File.OpenText(fileName); });
}
static IEnumerable<string> ReadLines(Func<TextReader> provider)
{
using (TextReader reader = provider())
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
}

6.2 C# 2:利用 yield 语句简化迭代器的更多相关文章

  1. Python生成器以及yield语句

    生成器是一种暂缓求值的技术,它可以用来生成一系列的值,但不会一次性生成所有的值,而只在需要的时候才计算和生成一个值. 通过yield语句构建生成器 要得到一个生成器,我们需要定义一个函数,这个函数返回 ...

  2. Python with yield语句

    1.with 语句 语法: with expression as variable 需要引入一个上下文管理协议,实现的方法是为一个类定义 __enter__() 和 __exit__() 方法, 在执 ...

  3. 机器学习实战 - 读书笔记(13) - 利用PCA来简化数据

    前言 最近在看Peter Harrington写的"机器学习实战",这是我的学习心得,这次是第13章 - 利用PCA来简化数据. 这里介绍,机器学习中的降维技术,可简化样品数据. ...

  4. javascript笔记04:let语句 和 yield语句 和 with语句

    1.yield语句: <script type="application/javascript; version=1.7"> function generator() ...

  5. 利用switch语句计算特定的年份的月份共有几天。

    //利用switch语句计算特定的年份的月份共有几天. let year =2015 let month =2 //先判断闰年中二月份的情况 ifmonth ==2 { if (year %400 = ...

  6. yield语句

        自C#的第一个版本以来,使用foreach语句可以轻松地迭代集合.在C#1.0中,创建枚举器仍需要做大量的工作.C#2.0添加了yield语句,以便于创建枚举器.yield return语句返 ...

  7. 【机器学习实战】第13章 利用 PCA 来简化数据

    第13章 利用 PCA 来简化数据 降维技术 场景 我们正通过电视观看体育比赛,在电视的显示器上有一个球. 显示器大概包含了100万像素点,而球则可能是由较少的像素点组成,例如说一千个像素点. 人们实 ...

  8. 利用while语句,条件为输入的字符不为'\n'.

    题目:输入一行字符,分别统计出其中英文字母.空格.数字和其它字符的个数. 1.程序分析:利用while语句,条件为输入的字符不为'\n'. 一个很简单的问题,其实换种方式就能完成,但是我就想怎么着才能 ...

  9. 生成器以及yield语句

    生成器以及yield语句最初的引入是为了让程序员可以更简单的编写用来产生值的序列的代码. 以前,要实现类似随机数生成器的东西,需要实现一个类或者一个模块,在生成数据的同时 保持对每次调用之间状态的跟踪 ...

随机推荐

  1. Smobiler实现列表展示—GridView(开发日志十二)

    一.列表功能展示   二.具体步骤 2.1,列表控件设计部分 2.1-① 在窗口SmoiblerForm1中加入gridview控件   2.1-② 在属性栏设置gridview控件的大小和位置   ...

  2. Codeforces Round #Pi (Div. 2) —— C-Geometric Progression

    题意: 如今有n个数,然后给出一个数k(代表的是等比数列中的那个公比),然后第二行给出n个数,代表的是这个序列. 最后的问题是叫你找出在这个序列中满足公比为k的三个数有几种.并输出方案总数. 思路: ...

  3. 菜鸟nginx源代码剖析 配置与部署篇(一) 手把手实现nginx &quot;I love you&quot;

    菜鸟nginx源代码剖析 配置与部署篇(一) 手把手配置nginx "I love you" Author:Echo Chen(陈斌) Email:chenb19870707@gm ...

  4. Hypercall

    在Linux中.大家应该对syscall很的了解和熟悉,其是用户态进入内核态的一种途径或者说是一种方式.完毕了两个模式之间的切换:而在虚拟环境中,有没有一种类似于syscall这样的方式.可以从no ...

  5. WPF学习笔记——没有前途的WPF

    看上去,WPF比silverlight有前途一点.毕竟,微软还没有宣布,WPF停止更新. 但我怀疑,不久的将来,WPF也会步其子集silverlight的后尘,要么不再出后续版本,要么向HTML5 + ...

  6. caioj1495: [视频]基于连通性状态压缩的 动态规划问题:Formula 2

    本来想写一天插头的,但是这题太难受(绝望)500+的代码量..我选择下午放松一下. 先ORZ一下苏大佬(yz的cdq啊%%%%%)居然把cdq论文里面的题抠出来出数据放在c站(呵呵真是个悲伤的故事不过 ...

  7. Android定时任务

    前言 我们在平常的开发中可能会遇到一些需求,比如说,每日定时提醒,定时更新数据等等,反正就是周期性任务,碰到这类需求,我们就可以叫做定时任务.以前我们可以通过使用线程Handler来实现,现在既然是在 ...

  8. Codeforces--630I--Parking Lot(规律)

     I - Parking Lot Crawling in process... Crawling failed Time Limit:500MS     Memory Limit:65536KB  ...

  9. 【专题系列】单调队列优化DP

    Tip:还有很多更有深度的题目,这里不再给出,只给了几道基本的题目(本来想继续更的,但是现在做的题目不是这一块内容,以后有空可能会继续补上) 单调队列——看起来就是很高级的玩意儿,显然是个队列,而且其 ...

  10. python 12:list(range(...)) (转化参数列表)

    numbers = list(range(1,11)) #把范围产生的数字串转化为列表储存 print(numbers) 运行结果应该是: [1,2,3,4,5,6,7,8,9,10]