迭代语句:foreach,in

foreach 语句对实现 System.Collections.IEnumerable 或 System.Collections.Generic.IEnumerable(T) 接口的数组或对象集合中的每个元素重复一组嵌入式语句。foreach语句用于循环访问集合,以获取您需要的信息,但不能用于在源集合中添加或移除项,否则可能产生不可预知的副作用。如果需要在源集合中添加或移除项,请使用 for 循环。

嵌入语句为数组或集合中的每个元素继续执行。当为集合中的所有元素完成迭代后,控制传递给 foreach 块之后的下一个语句。

可以在 foreach 块的任何点使用 break 关键字跳出循环,或使用 continue 关键字进入循环的下一轮迭代。

foreach 循环还可以通过 gotoreturn 或 throw 语句退出。

有关 foreach 关键字和代码示例的更多信息,请参见下面的主题:

对数组使用 foreach(C# 编程指南)

如何:使用 foreach 访问集合类(C# 编程指南)

示例

在此示例中,使用 foreach 显示整数数组的内容。

C#
class ForEachTest
{
    static void Main(string[] args)
    {
        int[] fibarray = new int[] { 0, 1, 2, 3, 5, 8, 13 };
        foreach (int i in fibarray)
        {
            System.Console.WriteLine(i);
        }
    }
}
/*
Output:
0
1
2
3
5
8
13
*/
本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!


 

对数组使用foreach

C# 还提供 foreach 语句。该语句提供一种简单、明了的方法来循环访问数组的元素。例如,下面的代码创建一个名为 numbers 的数组,并用 foreach 语句循环访问该数组:

C#
int[] numbers = { 4, 5, 6, 1, 2, 3, -2, -1, 0 };
foreach (int i in numbers)
{
    System.Console.Write("{0} ", i);
}
//Output: 4 5 6 1 2 3 -2 -1 0

本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

由于有了多维数组,可以使用相同方法来循环访问元素,例如:

C#
int[,] numbers2D = new int[3, 2] { { 9, 99 }, { 3, 33 }, { 5, 55 } };
// Or use the short form:
// int[,] numbers2D = { { 9, 99 }, { 3, 33 }, { 5, 55 } };

foreach (int i in numbers2D)
{
    System.Console.Write("{0} ", i);
}
// Output: 9 99 3 33 5 55

本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

然而,对于多维数组,使用嵌套的 for 循环可以更好地控制数组元素。

使用 foreach 访问集合类

下面的代码示例阐释如何编写可与 foreach 一起使用的非泛型集合类。该类是字符串标记化拆分器,类似于 C 运行时函数 strtok_s。

说明:

此示例描述的是仅当您无法使用泛型集合类时才采用的推荐做法。C# 语言和 .NET Framework 的 2.0 版和更高版本支持泛型。

本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

在下面的示例中,Tokens 使用“ ”和“-”作为分隔符将句子“This is a sample sentence.”拆分为标记,并使用 foreach 语句枚举这些标记:

C#
Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

foreach (string item in f)
{
    System.Console.WriteLine(item);
}

本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

Tokens 在内部使用一个数组,该数组自行实现 IEnumerator 和 IEnumerable。该代码示例本可以利用数组本身的枚举方法,但那样会使本示例的用意无法体现出来。

在 C# 中,集合类不一定要从 IEnumerable 和 IEnumerator 继承以便与 foreach 兼容。只要此类具有必需的 GetEnumeratorMoveNextReset 和 Current 成员,就可foreach 与一起使用。省略接口有一个好处:您可以将 Current 的返回类型定义得比 Object 更为明确,从而提供类型安全。

例如,从本主题中先前的示例代码开始,更改以下几行:

// No longer inherits from IEnumerable:
public class Tokens  
// Doesn't return an IEnumerator:
public TokenEnumerator GetEnumerator()  
// No longer inherits from IEnumerator:
public class TokenEnumerator  
// Type-safe: returns string, not object:
public string Current  
本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

现在,由于 Current 返回字符串,因此当 foreach 语句中使用了不兼容的类型时,编译器便能够检测到:

// Error: cannot convert string to int:
foreach (int item in f)  
本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!

省略 IEnumerable 和 IEnumerator 的缺点是,集合类不再能够与其他公共语言运行时兼容语言的 foreach 语句或等效项交互操作。

您可以同时拥有两者的优点,即 C# 中的类型安全以及与其他公共语言运行时兼容语言的互操作性,方法是从 IEnumerable 和 IEnumerator 继承并使用显式接口实现,如下面的示例所示。

示例

C#
using System.Collections;

// Declare the Tokens class:
public class Tokens : IEnumerable
{
    private string[] elements;

    Tokens(string source, char[] delimiters)
    {
        // Parse the string into tokens:
        elements = source.Split(delimiters);
    }

    // IEnumerable Interface Implementation:
    //   Declaration of the GetEnumerator() method 
    //   required by IEnumerable
    public IEnumerator GetEnumerator()
    {
        return new TokenEnumerator(this);
    }


    // Inner class implements IEnumerator interface:
    private class TokenEnumerator : IEnumerator
    {
        private int position = -1;
        private Tokens t;

        public TokenEnumerator(Tokens t)
        {
            this.t = t;
        }

        // Declare the MoveNext method required by IEnumerator:
        public bool MoveNext()
        {
            if (position < t.elements.Length - 1)
            {
                position++;
                return true;
            }
            else
            {
                return false;
            }
        }

        // Declare the Reset method required by IEnumerator:
        public void Reset()
        {
            position = -1;
        }

        // Declare the Current property required by IEnumerator:
        public object Current
        {
            get
            {
                return t.elements[position];
            }
        }
    }


    // Test Tokens, TokenEnumerator
    static void Main()
    {
        // Testing Tokens by breaking the string into tokens:
        Tokens f = new Tokens("This is a sample sentence.", new char[] {' ','-'});

        foreach (string item in f)
        {
            System.Console.WriteLine(item);
        }
    }
}
/* Output:
    This
    is
    a
    sample
    sentence.  
*/
本在线速查手册由www.w:3:x:u:e.com提供,请勿盗用!