C# IEnumerable
上次修改时间:2024 年 2 月 2 日
在本文中,我们将解释 C# IEnumerable 接口。
IEnumerable 是一个标准的 C# 接口,它允许使用 foreach 循环迭代集合。 IEnumerable 在内部使用 IEnumerator。 它用于执行迭代。 它控制列表中从一个元素移动到下一个元素。
实现 IEnumerable 接口的对象必须定义 GetEnumerator 方法,该方法返回 IEnumerator。 IEnumerator 实现了 MoveNext、Reset 和 Current 方法。
此外,IEnumerable 还支持 C# 中的生成器,使用 yield return 和 yield break 语句,并且它与 LINQ 结合使用,用于集合中的数据操作。
启用 foreach 迭代
IEnumerable 使与 foreach 关键字的无缝交互成为可能。
IEnumerable<int> range = Enumerable.Range(1, 6);
List<string> words = ["sky", "cup", "beer"];
IEnumerable<char> chars = "an old falcon".AsEnumerable();
decimal[] vals = [1m, 2m, 3m];
DoIteration(range);
DoIteration(words);
DoIteration(chars);
DoIteration(vals.AsEnumerable());
void DoIteration<T>(IEnumerable<T> vals)
{
foreach (var e in vals)
{
Console.Write($"{e} ");
}
Console.WriteLine();
}
在该程序中,我们定义了一个泛型 DoIteration 方法,该方法迭代一系列数字、单词列表、字符序列和字符数组。
IEnumerable<char> chars = "an old falcon".AsEnumerable();
使用 AsEnumerable 将字符串转换为字符序列。
void DoIteration<T>(IEnumerable<T> vals)
DoIteration 方法将泛型 IEnumerable 作为参数。
foreach (var e in vals)
{
Console.Write($"{e} ");
}
我们使用 foreach 遍历传递的参数。
$ dotnet run 1 2 3 4 5 6 sky cup beer a n o l d f a l c o n 1 2 3
IEnumerable 和生成器
下一个程序我们从生成器创建一个元组的 IEnumerable。
int n = 10;
IEnumerable<string> res = FibSeq().TakeWhile(f => f.n <= n).Select(f => $"{f.fib}");
Console.WriteLine(string.Join(" ", res));
IEnumerable<(int n, int fib)> FibSeq()
{
yield return (0, 0);
yield return (1, 1);
var (x, y, n) = (1, 0, 0);
while (x < int.MaxValue - y)
{
(x, y, n) = (x + y, x, n + 1);
yield return (n, x);
}
}
在该示例中,我们计算斐波那契数列。
IEnumerable<string> res = FibSeq().TakeWhile(f => f.n <= n).Select(f => $"{f.fib}");
我们使用 LINQ 的 TakeWhile 方法使用斐波那契数列。
Console.WriteLine(string.Join(" ", res));
字符串序列被连接起来。
IEnumerable<(int n, int fib)> FibSeq()
{
yield return (0, 0);
yield return (1, 1);
var (x, y, n) = (1, 0, 0);
while (x < int.MaxValue - y)
{
(x, y, n) = (x + y, x, n + 1);
yield return (n, x);
}
}
FibSeq 方法返回元组值的序列。 每个元组包含 n 值,我们生成序列的上限,以及当前的斐波那契值 fib。
yield return (0, 0); yield return (1, 1);
前两个元组使用 yield return 返回。
var (x, y, n) = (1, 0, 0);
while (x < int.MaxValue - y)
{
(x, y, n) = (x + y, x, n + 1);
yield return (n, x);
}
序列的其余部分使用 while 循环计算。 序列最多达到 int.MaxValue。
带有自定义类的 IEnumerable
在下一个示例中,我们创建一个可枚举的自定义类。
using System.Collections;
Bag bag = new();
foreach (object e in bag)
{
Console.WriteLine(e);
}
class Bag : IEnumerable<object>
{
private readonly object[] data = [1, "falcon", 4.4m, new DateTime(2024, 01, 31)];
public IEnumerator<object> GetEnumerator()
{
foreach (var item in data)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
我们定义一个 Bag 类,可以使用 foreach 循环遍历它。
class Bag : IEnumerable<object>
{
private readonly object[] data = [1, "falcon", 4.4m, new DateTime(2024, 01, 31)];
public IEnumerator<object> GetEnumerator()
{
foreach (var item in data)
{
yield return item;
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
自定义类实现了 IEnumerable 接口。 Bag 类定义了 GetEnumerator 方法。 它使用 yield return 从 data 数组生成数据。
$ dotnet run 1 falcon 4,4 31. 1. 2024 0:00:00
带有查询表达式的 IEnumerable
LINQ 查询表达式返回 IEnumerables,稍后可以使用 foreach 迭代它们。
IEnumerable<int> vals = from value in Enumerable.Range(0, 5)
select value;
foreach (var e in vals)
{
Console.WriteLine(e);
}
List<string> words = [ "sky", "forest", "war", "buy",
"crypto", "cup", "water", "cloud" ];
IEnumerable<string> res = from word in words
where word.StartsWith('c')
select word;
Console.WriteLine(string.Join(',', res));
在该示例中,我们迭代两个查询表达式:一个整数范围和一个单词列表。
$ dotnet run 0 1 2 3 4 crypto,cup,cloud
来源
在本文中,我们介绍了 C# IEnumerable 接口。
作者
列出所有 C# 教程。