迭代器是一种特殊类型的对象,可以遍历集合对象中的元素,不必在代码中显式使用for或while循环。迭代器通常由 IEnumerable 和 IEnumerator 接口共同实现。。
源码:
IEnumerable 接口只定义了一个方法 GetEnumerator(),该方法返回一个迭代器对象,该对象实现了 IEnumerator 接口。
public interface IEnumerable
{
// Interfaces are not serializable
// Returns an IEnumerator for this enumerable Object. The enumerator provides
// a simple way to access all the contents of a collection.
IEnumerator GetEnumerator();
}
//枚举器提供了一种访问集合的所有内容的简单方法。
IEnumerator 接口定义了三个方法: MoveNext() 在迭代器中将游标移动到下一个元素; Current 返回集合内位于游标当前位置的元素;Reset() 将游标返回到集合中的第一个元素之前;
public interface IEnumerator
{
// Interfaces are not serializable
// Advances the enumerator to the next element of the enumeration and
// returns a boolean indicating whether an element is available. Upon
// creation, an enumerator is conceptually positioned before the first
// element of the enumeration, and the first call to MoveNext
// brings the first element of the enumeration into view.
//
bool MoveNext();
// Returns the current element of the enumeration. The returned value is
// undefined before the first call to MoveNext and following a
// call to MoveNext that returned false. Multiple calls to
// GetCurrent with no intervening calls to MoveNext
// will return the same object.
//
Object Current {
get;
}
// Resets the enumerator to the beginning of the enumeration, starting over.
// The preferred behavior for Reset is to return the exact same enumeration.
// This means if you modify the underlying collection then call Reset, your
// IEnumerator will be invalid, just as it would have been if you had called
// MoveNext or Current.
// 如果修改了基础集合,然后调用Reset,则IEnumerator将无效
void Reset();
}
迭代器的使用:
1.C#里的集合(Array;List;Dictionary;Queue;Stack;HashSet...)都实现了迭代器(实现IEnumerable接口和IEnumerator接口);实现了迭代器的集合可以使用foreach来遍历访问。
2.异步编程(使用Task和async/await关键字来实现异步调用)
3.LINQ
4.Unity协程
*for循环是不需要使用迭代器来遍历的,它通过创建和维护一个索引变量并使用索引来获取集合中的元素。
*foreach循环需要使用迭代器来遍历集合中的元素,它使用GetEnumerator()方法来获取集合的迭代器,然后使用MoveNext和Current来遍历集合中的元素。
下面是foreach循环简化版的代码:
//获取迭代器并且遍历
IEnumerator enumerator = myCollection.GetEnumerator();
while (enumerator.MoveNext())
{
object item = enumerator.Current;
func() {
...自定义的方法...
}
}
enumerator.Dispose();
使用迭代器来实现异步编程:
// 定义一个返回IEnumerable<Task<string>> 类型的迭代器方法
public static IEnumerable<Task<string>> GetAsyncTasks(string[] urls)
{
using (HttpClient httpClient = new HttpClient())
{
foreach (var url in urls)
{
// 发送异步请求
Task<string> task = httpClient.GetStringAsync(url);
// 将异步任务通过yield return语句返回
yield return task;
}
}
}
// 使用foreach语句遍历异步任务
public static async Task Main(string[] args)
{
string[] urls = { "https://www.example.com", "https://www.google.com", "https://www.microsoft.com" };
foreach (var task in GetAsyncTasks(urls))
{
// 等待每个异步任务结束
string result = await task;
Console.WriteLine(result);
}
}
//使用yield return关键字将每个异步请求任务返回;
//使用foreach语句遍历每个异步任务
//并使用await关键字等待异步任务完成;
//这样就可以实现协作式异步调用,通过迭代器来逐个执行异步任务。
使用迭代器实现C#的LINQ的例子:(实现简单的Where和Select方法)
using System;
using System.Collections.Generic;
public static class LinqExtensions
{
// 定义一个扩展方法Where,用于过滤数据
public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (TSource item in source)
{
if (predicate(item))
{
yield return item;
}
}
}
// 定义一个扩展方法Select,用于投影数据
public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, TResult> selector)
{
foreach (TSource item in source)
{
yield return selector(item);
}
}
}
public class Program
{
public static void Main(string[] args)
{
int[] nums = { 1, 2, 3, 4, 5 };
// 使用迭代器实现简单的Where和Select方法
var result = nums.Where(n => n % 2 == 0)
.Select(n => n * n);
// 输出结果
foreach (var item in result)
{
Console.WriteLine(item);
}
}
}
//使用了扩展方法Where和Select,
//使用yield return语句将每次遍历的数据元素传递给下一次操作,
//实现了对数据的过滤和投影操作。
//这样,我们就可以通过组合这些操作来构建LINQ查询,而不必显式地创建中间集合,从而提高代码的性能表现。
//需要注意的是,在实现迭代器的操作时,需要正确处理资源的释放和异常处理,以免出现内存泄漏等问题。
//另外,需要充分考虑数据可枚举性和延迟执行等问题,以便实现最佳的代码性能和效率。