案例一:
public class Order
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
public IEnumerable<DateTime> DateRange
{
get
{
for (DateTime day = StartDate; day <= EndDate; day = day.AddDays(1))
{
yield return day;
}
}
}
}
Order order = new Order
{
StartDate = DateTime.Now,
EndDate = DateTime.Now.AddDays(31)
};
#region 不使用迭代器
for (DateTime day = order.StartDate; day <= order.EndDate; day = day.AddDays(1))
{
Console.WriteLine(day);
}
#endregion
Console.WriteLine("********************************************");
#region 使用迭代器
foreach (var dateTime in order.DateRange)
{
Console.WriteLine(dateTime);
}
#endregion
案例二:
class Program
{
static void Main(string[] args)
{
string path = "";
using (TextReader reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
Console.WriteLine(line);
}
}
//下面是对上面这段代码的封装
#region 版本1
TextReader tr = File.OpenText(path);
ReadFile(tr, Console.WriteLine);// ,这里之所以可以这样简写委托实例,是因为 Console.WriteLine() 方法有很多重载,利用了 "Method Group"的概念
#endregion
#region 版本2
foreach (var line in ReadLines(path))
{
Console.WriteLine(line);
}
#endregion
Console.ReadKey();
}
#region 版本1
static void ReadFile(TextReader reader, Action<string> action)
{
string line;
while ((line = reader.ReadLine()) != null)
{
action(line);
}
reader.Close();
reader.Dispose();
}
#endregion
//这个版本的弊端是:reader 在方法内部创建,限制了编码格式,如果调用者突然想用其他编码方式,则无法使用该方法
#region 版本2
static IEnumerable<string> ProcessFile(string path)
{
using (TextReader reader = File.OpenText(path))
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
#endregion
//如果我们想使用不用的编码格式呢?
//所以 reader 的创建还是要交换给调用者
//但是这个方案最大的弊端是:需要调用者自己清理 reader
#region 版本3
static IEnumerable<string> ReadLines(TextReader reader)
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
#endregion
//利用委托,延迟 reader 的创建
//即,我们只有在需要的时候才去获取资源
#region 终极版本
static IEnumerable<string> ReadLines(Func<TextReader> provider)
{
using (TextReader reader = provider())
{
string line;
while ((line = reader.ReadLine()) != null)
{
yield return line;
}
}
}
static IEnumerable<string> ReadLines(string path)
{
return ReadLines(path, Encoding.UTF8);
}
static IEnumerable<string> ReadLines(string path, Encoding encoding)
{
return ReadLines(() => new StreamReader(path, encoding));
}
#endregion
}
案例三:
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
//当我们调用 where 方法时,我们理所当然的认为会立刻进行参数的校验
//但实际上不是,因为在 where 方法里面有 yield return 语句,也就是说:这个 where 方法是一个迭代器块
//而迭代器块具有延迟执行的特性
//意思就是,当我们调用 where 方法的时候,并不会立刻执行方法内部的参数校验,
//而是要等到 foreach 语句的 in 指令时,才会执行
//同时,由于 yield return 语句返回的类型必须是实现了 IEnumerable 或者 IEnumerable<T> 接口的类型
var result = WhereGood(list, s => s % 2 == 0);
foreach (var i in result)
{
Console.WriteLine(i);
}
Console.ReadKey();
}
#region 不好的写法
static IEnumerable<T> Where<T>(IEnumerable<T> source, Predicate<T> predicate)
{
if (source == null || predicate == null)
{
Console.WriteLine("入参错误!");
throw new Exception("入参错误");
}
foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
#endregion
#region 好的写法,校验参数和逻辑代码分开写
static IEnumerable<T> WhereGood<T>(IEnumerable<T> source, Predicate<T> predicate)
{
if (source == null || predicate == null)
{
Console.WriteLine("入参错误!");
throw new Exception("入参错误");
}
//同样,这里不会立刻执行 GoWhere() 方法,直到 执行到 foreach 中的 in
return GoWhere(source, predicate);
}
static IEnumerable<T> GoWhere<T>(IEnumerable<T> source, Predicate<T> predicate)
{
foreach (var item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
#endregion