(精华)2020年8月11日 C#基础知识点 yield迭代器的使用
基本使用
/// <summary>
/// 含有yield的函数说明它是一个生成器,而不是普通的函数。当程序运行到yield这一行时,该函数会返回值,并保存当前域的所有变量状态;
/// 等到该函数下一次被调用时,会从上一次中断的地方开始执行,一直遇到下一个yield, 程序返回值, 并在此保存当前状态; 如此反复,直到函数正常执行完成。
/// 迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式。
/// 简单来说,迭代器模式使得你能够获取到序列中的所有元素 而不用关心是其类型是array,list,linked list或者是其他什么序列结构。
/// 这一点使得能够非常高效的构建数据处理通道(data pipeline)--即数据能够进入处理通道,进行一系列的变换,或者过滤,然后得到结果。事实上,这正是LINQ的核心模式。
/// 在.NET中,迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接 口,那么就能够被迭代;
/// 调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。迭代器类似数据库中的游标,他是 数据序列中的一个位置记录。
/// 迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。
/// </summary>
public class YieldShow
{<!-- -->
public void Show()
{<!-- -->
IEnumerable<int> iterable = this.CreateEnumerable();//1 不会直接执行
//IEnumerator iterator = iterable.GetEnumerator();
IEnumerator<int> iterator = iterable.GetEnumerator();
Console.WriteLine("开始迭代");
while (true)
{<!-- -->
Console.WriteLine("调用MoveNext方法……");
Boolean result = iterator.MoveNext();//2 正式开启CreateEnumerable
Console.WriteLine("MoveNext方法返回的{0}", result);
if (!result)
{<!-- -->
break;
}
Console.WriteLine("获取当前值……");
Console.WriteLine("获取到的当前值为{0}", iterator.Current);
}
Console.ReadKey();
}
/// <summary>
/// 普通获取数据
/// </summary>
/// <returns></returns>
public IEnumerable<int> CommonMethod()
{<!-- -->
List<int> results = new List<int>();
int counter = 0;
int result = 1;
while (counter++ < 10)
{<!-- -->
Thread.Sleep(1000);
Console.WriteLine($"获取{counter}次数据");
result = result * 2;
results.Add(result);
}
return results;
}
/// <summary>
/// yield获取数据
/// </summary>
/// <returns></returns>
public IEnumerable<int> YieldMethod()
{<!-- -->
int counter = 0;
int result = 1;
while (counter++ < 10)
{<!-- -->
Thread.Sleep(1000);
Console.WriteLine($"获取{counter}次数据");
result = result * 2;
yield return result;
}
}
public IEnumerable<int> CreateEnumerable()
{<!-- -->
try
{<!-- -->
Console.WriteLine("{0} CreateEnumerable()方法开始", DateTime.Now);
for (int i = 0; i < 5; i++)
{<!-- -->
Console.WriteLine("{0}开始 yield {1}", DateTime.Now, i);
yield return i;
Console.WriteLine("{0}yield 结束", DateTime.Now);
if (i == 4)
{<!-- -->
yield break;//直接终结迭代 4会出现的,,
}
}
Console.WriteLine("{0} Yielding最后一个值", DateTime.Now);
yield return -1;
Console.WriteLine("{0} CreateEnumerable()方法结束", DateTime.Now);
}
finally
{<!-- -->
Console.WriteLine("停止迭代!");
}
}
}
延迟加载实现原理
/// <summary>
/// 1 迭代器模式 Iterator
/// 2 .net里面的迭代器模式 yield return
/// 3 解密linq to object的延迟查询,按需获取
/// </summary>
class Program
{<!-- -->
static void Main(string[] args)
{<!-- -->
try
{<!-- -->
#region Show
{<!-- -->
Console.WriteLine("**********************");
YieldShow yieldShow = new YieldShow();
yieldShow.Show();
Console.WriteLine("**********************");
LinqExtendShow.Show();
Console.WriteLine("**********************");
CustomCollection collection = new CustomCollection();
List<int> intList = collection.GetData();
for (int i = 0; i < intList.Count(); i++)
{<!-- -->
Console.WriteLine(intList[i]);
}
Console.WriteLine("**********************");
foreach (var item in collection)
{<!-- -->
Console.WriteLine(item);//按需获取,延迟查询
}
}
//LinqExtendShow.Show();
#endregion
}
catch (Exception ex)
{<!-- -->
Console.WriteLine(ex.Message);
}
Console.Read();
}
}
/// <summary>
/// 含有yield的函数说明它是一个生成器,而不是普通的函数。当程序运行到yield这一行时,该函数会返回值,并保存当前域的所有变量状态;等到该函数下一次被调用时,会从上一次中断的地方开始执行,一直遇到下一个yield, 程序返回值, 并在此保存当前状态; 如此反复,直到函数正常执行完成。
/// 迭代器模式是设计模式中行为模式(behavioral pattern)的一个例子,他是一种简化对象间通讯的模式,也是一种非常容易理解和使用的模式。简单来说,迭代器模式使得你能够获取到序列中的所有元素 而不用关心是其类型是array,list,linked list或者是其他什么序列结构。这一点使得能够非常高效的构建数据处理通道(data pipeline)
/// --即数据能够进入处理通道,进行一系列的变换,或者过滤,然后得到结果。事实上,这正是LINQ的核心模式。
/// 在.NET中,迭代器模式被IEnumerator和IEnumerable及其对应的泛型接口所封装。如果一个类实现了IEnumerable接 口,那么就能够被迭代;调用GetEnumerator方法将返回IEnumerator接口的实现,它就是迭代器本身。迭代器类似数据库中的游标,他是 数据序列中的一个位置记录。迭代器只能向前移动,同一数据序列中可以有多个迭代器同时对数据进行操作。
/// </summary>
public class YieldShow
{<!-- -->
public IEnumerable<int> CreateEnumerable()
{<!-- -->
try
{<!-- -->
Console.WriteLine("{0} CreateEnumerable()方法开始", DateTime.Now);
for (int i = 0; i < 5; i++)
{<!-- -->
Console.WriteLine("{0}开始 yield {1}", DateTime.Now, i);
yield return i;
Console.WriteLine("{0}yield 结束", DateTime.Now);
if (i == 4)
{<!-- -->
yield break;//直接终结迭代,4会出现的.
}
}
Console.WriteLine("{0} Yielding最后一个值", DateTime.Now);
yield return -1;
Console.WriteLine("{0} CreateEnumerable()方法结束", DateTime.Now);
}
finally
{<!-- -->
Console.WriteLine("停止迭代!");
}
}
/// <summary>
/// MoveNext 检查是否存在 并设置current
/// </summary>
public void Show()
{<!-- -->
//不会直接执行
IEnumerable<int> iterable = this.CreateEnumerable();
//返回迭代器
IEnumerator<int> iterator = iterable.GetEnumerator();
Console.WriteLine("开始迭代");
while (true)
{<!-- -->
Console.WriteLine("调用MoveNext方法……");
Boolean result = iterator.MoveNext();//2 正式开启CreateEnumerable
Console.WriteLine("MoveNext方法返回的{0}", result);
if (!result)
{<!-- -->
break;
}
Console.WriteLine("获取当前值……");
Console.WriteLine("获取到的当前值为{0}", iterator.Current);
}
Console.ReadKey();
}
}
public class Student
{<!-- -->
public int Id {<!-- --> get; set; }
public int ClassId {<!-- --> get; set; }
public string Name {<!-- --> get; set; }
public int Age {<!-- --> get; set; }
public void Study()
{<!-- -->
Console.WriteLine("{0} {1}是大神", this.Id, this.Name);
}
}
public class LinqExtendShow
{<!-- -->
/// <summary>
/// 准备数据
/// </summary>
/// <returns></returns>
private static List<Student> GetStudentList()
{<!-- -->
#region 初始化数据
List<Student> studentList = new List<Student>()
{<!-- -->
new Student()
{<!-- -->
Id=1,
Name="打兔子的猎人",
ClassId=2,
Age=35
},
new Student()
{<!-- -->
Id=1,
Name="Alpha Go",
ClassId=2,
Age=23
},
new Student()
{<!-- -->
Id=1,
Name="白开水",
ClassId=2,
Age=27
},
new Student()
{<!-- -->
Id=1,
Name="狼牙道",
ClassId=2,
Age=26
},
new Student()
{<!-- -->
Id=1,
Name="Nine",
ClassId=2,
Age=25
},
new Student()
{<!-- -->
Id=1,
Name="Y",
ClassId=2,
Age=24
},
new Student()
{<!-- -->
Id=1,
Name="小昶",
ClassId=2,
Age=21
},
new Student()
{<!-- -->
Id=1,
Name="yoyo",
ClassId=2,
Age=22
},
new Student()
{<!-- -->
Id=1,
Name="冰亮",
ClassId=2,
Age=34
},
new Student()
{<!-- -->
Id=1,
Name="瀚",
ClassId=2,
Age=30
},
new Student()
{<!-- -->
Id=1,
Name="毕帆",
ClassId=2,
Age=30
},
new Student()
{<!-- -->
Id=1,
Name="一点半",
ClassId=2,
Age=30
},
new Student()
{<!-- -->
Id=1,
Name="小石头",
ClassId=2,
Age=28
},
new Student()
{<!-- -->
Id=1,
Name="大海",
ClassId=2,
Age=30
},
new Student()
{<!-- -->
Id=3,
Name="yoyo",
ClassId=3,
Age=30
},
new Student()
{<!-- -->
Id=4,
Name="unknown",
ClassId=4,
Age=30
}
};
#endregion
return studentList;
}
public static void Show()
{<!-- -->
List<Student> studentList = GetStudentList();
var result = studentList.Where(s => s.Age < 30);
var list = studentList.TestWhere<Student>(s =>
{<!-- -->
Console.WriteLine("1234678");//迭代器的延迟
return s.Age < 30;
});
foreach (var item in list)
{<!-- -->
Console.WriteLine($"Name={item.Name} Age={item.Age}");
}
}
}
public static class LinqExtend
{<!-- -->
public static IEnumerable<TSource> TestWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{<!-- -->
if (source == null)
{<!-- -->
throw new Exception("source");
}
if (predicate == null)
{<!-- -->
throw new Exception("predicate");
}
return new EnumeratorIterator<TSource>(source, predicate);
}
}
public class EnumeratorIterator<TSource> : IEnumerable<TSource>
{<!-- -->
private IEnumerable<TSource> source;
private Func<TSource, bool> predicate;
public EnumeratorIterator(IEnumerable<TSource> source, Func<TSource, bool> predicate)
{<!-- -->
this.source = source;
this.predicate = predicate;
}
public IEnumerator<TSource> GetEnumerator()
{<!-- -->
foreach (var item in this.source)
{<!-- -->
if (predicate(item))
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{<!-- -->
foreach (var item in this.source)
{<!-- -->
if (predicate(item))
yield return item;
}
}
}
/// <summary>
/// 集合:数据结构和访问方法
/// </summary>
public class CustomCollection //: IEnumerable
{<!-- -->
/// <summary>
/// 获取全部数据
/// </summary>
/// <returns></returns>
public List<int> GetData()
{<!-- -->
List<int> intList = new List<int>();
for (int i = 0; i < 10; i++)
{<!-- -->
intList.Add(this.Get());
}
return intList;
}
/// <summary>
/// 遍历
/// </summary>
/// <returns></returns>
public IEnumerator GetEnumerator()
{<!-- -->
for (int i = 0; i < 10; i++)
{<!-- -->
yield return Get();
}
}
private int Get()
{<!-- -->
Thread.Sleep(1000);
return DateTime.Now.Second;
}
}