ZetCode

C# IEnumerable

上次修改时间:2024 年 2 月 2 日

在本文中,我们将解释 C# IEnumerable 接口。

IEnumerable 是一个标准的 C# 接口,它允许使用 foreach 循环迭代集合。 IEnumerable 在内部使用 IEnumerator。 它用于执行迭代。 它控制列表中从一个元素移动到下一个元素。

实现 IEnumerable 接口的对象必须定义 GetEnumerator 方法,该方法返回 IEnumeratorIEnumerator 实现了 MoveNextResetCurrent 方法。

此外,IEnumerable 还支持 C# 中的生成器,使用 yield returnyield break 语句,并且它与 LINQ 结合使用,用于集合中的数据操作。

启用 foreach 迭代

IEnumerable 使与 foreach 关键字的无缝交互成为可能。

Program.cs
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

Program.cs
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

在下一个示例中,我们创建一个可枚举的自定义类。

Program.cs
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 returndata 数组生成数据。

$ dotnet run
1
falcon
4,4
31. 1. 2024 0:00:00

带有查询表达式的 IEnumerable

LINQ 查询表达式返回 IEnumerables,稍后可以使用 foreach 迭代它们。

Program.cs
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

来源

IEnumerable<T> 接口 - 语言参考

在本文中,我们介绍了 C# IEnumerable 接口。

作者

我叫 Jan Bodnar,是一位充满热情的程序员,拥有丰富的编程经验。 我自 2007 年以来一直撰写编程文章。迄今为止,我已经撰写了超过 1,400 篇文章和 8 本电子书。 我拥有超过十年的编程教学经验。

列出所有 C# 教程