Foreach用法

 

 

循环语句是编程的基本语句,在C#中除了沿用C语言的循环语句外,还提供了foreach语句来实现循环。那么我要说的就是,在循环操作中尽量使用foreach语句来实现。
 
为了来更好地说明为什么要提倡使用foreach,用如下三种不同方式来编写循环语句。
        int[] nArray = new int[100];
 
        // Use "foreach" to loop array
        foreach( int i in nArray )
            Debug.WriteLine( i.ToString() );
 
        // Use "for" to loop array
        for( int i = 0; i < nArray.Length; i++ )
            Debug.WriteLine( nArray[i].ToString() );
 
        // Another way using "for" to loop array
        int nLength = nArray.Length;
        for( int i = 0; i < nLength; i++ )
            Debug.WriteLine( nArray[i].ToString() );
 
很明显,foreach语句很简洁,但是它的优点不仅仅在于此,它的效率也是最高的。可能很多人认为最后一种的效率会更高,因为表面上看着不用每次访问引用类型的属性。可是它却是三者当中,效率最低的。因为C#是强类型检查,那么对于数组访问的时候,要对索引的有效值进行判断,那么对于最后一种代码实际产生的效果如同下面的代码一样。
        // Another way using "for" to loop array
        int nLength = nArray.Length;
        for( int i = 0; i < nLength; i++ )
        {
            if( i < nArray.Length )
                Debug.WriteLine( nArray[i].ToString() );
            else
                throw new IndexOutOfRangeException();
        }
(书中这里有些出入,经过网友sozdream的提示,在1.1环境下发现最后一种方法是最快的,前两者的速度基本相等;通过Dissambly查看最后一种循环方法所产生的代码,并没有产生类似于文章所说的那种索引检查。不过还是不建议使用最后一种,因为此方法对索引的判断有些脱节,尤其是当循环中数组尺寸发生变化的时候,索引有效检查无法及时进行)
 
foreach语句除了简洁和高效外,还有很多优点,接下来一一列举。
 
第一个就是不用考虑数组起始索引是几,很多人可能从其他语言转到C#的,那么原先语言的起始索引可能不是1,例如VB或者Delphi语言,那么在C#中使用数组的时候就难免疑问到底使用0开始还是用1开始呢,那么使用foreach就可以避免这类问题。
 
第二个好处就是对于多维数组操作用foreach就非常简便了,例如:
        int[,] nVisited = new int[8,8];
        // Use "for" to loop two-dimension array
        for( int i = 0; i < nVisited.GetLength(0); i++ )
            for( int j = 0; j < nVisited.GetLength( 1 ); j++ )
                Debug.WriteLine( nVisited[i,j].ToString() );
 
        // Use "foreach" to loop two-dimension array
        foreach( int i in nVisited )
            Debug.WriteLine( i.ToString() );
 
对于三维或更多维,foreach语句不用发生任何变化,而对于for语句来说就要进行修改了,这里就不多说了。
 
第三个要说的就是foreach完成类型转换操作,这种体现可能通过如上的例子看不出任何效果,但是对于ArrayList之类的数据集来说,这种操作就显得比较突出,例如:
        // Init an arraylist object
        int[] nArray = new int[100];
        ArrayList arrInt = new ArrayList();
        arrInt.AddRange( nArray );
 
        // Use "foreach" to loop an arraylist
        foreach( int i in arrInt )
            Debug.WriteLine( i.ToString() );
 
        // Use "for" to loop an arraylist
        for( int i = 0; i < arrInt.Count; i++ )
        {
            int n = ( int ) arrInt[i];
            Debug.WriteLine( n.ToString() );
        }
 
最后要说的是使用foreach并没有增加资源使用,这句话听得有些难懂,由于对于继承了IEnumerable接口的类型数据,才能使用foreach语句,那么对于使用foreach会访问IEnumerable接口中GetEnumerator方法来进行枚举,那么对于如上的foreach语句,对应的语句其实如下:
        IEnumerator it = arrInt.GetEnumerator() as IEnumerator;
        using( IDisposable disp = it as IDisposable )
        {
            while( it.MoveNext() )
            {
                int elem = ( int )it.Current;
                Debug.WriteLine( elem.ToString() );
            }
        }
 
也就是说在出了foreach之后对于IEnumerator的对象也进行Dispose处理。
 
对于foreach说了这么多好处,那么在使用它是否可以无懈可击呢。其实不是这样的,foreach语句中有两个限制,第一不能修改枚举成员,其次不要对集合进行删除操作。也就是如下两种方式都是错误的。
        // Use "foreach" to loop an arraylist
        foreach( int i in arrInt )
        {
            i++;//Can't be compiled
            Debug.WriteLine( i.ToString() );
        }
 
        // Use "foreach" to loop an arraylist
        foreach( int i in arrInt )
        {
            arrInt.Remove( i );//It will generate error in run-time
            Debug.WriteLine( i.ToString() );
        }
 
那么对于如上两个操作,可以用for来实现,此外这里多说一句,就是对于一个记录集的多条数据删除问题,也是经常出现问题的地方(论坛上经常问类似的问题),由于在一些记录集中进行删除的时候,在删除操作之后相应的索引也发生了变化,这时候的删除要反过来进行删除,大致形式如下。
        // Use "for" to loop an arraylist
        for( int i = arrInt.Count - 1; i >=0; i-- )
        {
            int n = ( int ) arrInt[i];
            if( n == 5 )
                arrInt.RemoveAt( i ); // Remove data here
            Debug.WriteLine( n.ToString() );
        }
 
除了这两个地方外,foreach可以基本适用于任何循环,因此对于循环的编写要尽量使用foreach,因为它会使你的代码清晰简洁,又不失高效。
 
<think>好的,我现在需要回答用户关于foreach语法及示例用法的问题。用户可能对foreach在不同编程语言中的使用不太清楚,需要详细解释。首先,我要回忆一下常见的几种语言中的foreach结构,比如Java、C#、Python等,然后根据提供的引用资料来整理答案。 首先,用户提供的引用中有Java、C#的相关内容,还有关于foreach的一般性描述。需要确保回答覆盖这些内容,并且结构清晰。根据系统指令,要分点回答,每个部分可能有语法和示例,还要注意使用正确的LaTeX格式,比如行内公式用$...$,独立公式用$$...$$,不过这个问题可能不需要数学公式,但需要代码块。同时,要生成相关问题,放在最后。 接下来,我需要整理各个语言foreach用法。例如,Java中使用增强for循环,C#中的foreach语法,Python中的for循环本质上也是foreach风格。可能需要指出不同语言中的差异,比如Java的forEach()方法和for-each循环的区别,如引用4提到的。 需要注意用户可能混淆了forEach方法和for-each循环,需要明确区分。例如在Java中,for-each是语法结构,而forEach()是集合的方法,接受lambda表达式。引用3提到foreach是语法糖,可以简化代码,提高可读性,这点需要强调。 然后,要检查提供的引用内容,确保正确引用。例如,引用1和引用4是关于Java的,引用2是C#,引用3是通用描述。示例代码需要正确展示不同语言的语法,比如Java的数组遍历,C#的字典遍历等。 还需要注意用户的问题可能希望了解基本语法和示例,所以每个部分应该包括语法说明和代码示例。例如,Java的for-each循环结构,C#foreach语法,Python的for循环,以及JavaScript的forEach方法。此外,可以提到注意事项,比如在遍历过程中不能修改集合,否则可能引发异常。 最后,生成的相关问题需要与foreach相关,可能涉及不同语言的区别、常见错误、性能比较等。需要确保问题有针对性,帮助用户进一步学习。 现在,按照这些思路组织内容,确保符合格式要求,使用正确的代码块标注语言,引用正确来源,并在末尾添加相关问题。</think>### `foreach` 语法及示例用法 `foreach` 是一种用于遍历集合(如数组、列表、字典等)的循环结构,其核心目标是简化代码并提高可读性。不同编程语言的实现略有差异,以下是常见语言中的语法及示例: --- #### 1. **Java 中的 `for-each` 循环** - **语法**: ```java for (元素类型 变量名 : 集合) { // 处理每个元素 } ``` - **示例**: ```java // 遍历数组 int[] numbers = {1, 2, 3}; for (int num : numbers) { System.out.println(num); } // 遍历列表 List<String> fruits = Arrays.asList("Apple", "Banana"); for (String fruit : fruits) { System.out.println(fruit); } ``` **注意**:Java 的 `for-each` 是语法层面的实现,底层依赖迭代器。遍历时不可直接修改集合结构(如删除元素),否则会抛出 `ConcurrentModificationException`[^4]。 --- #### 2. **C# 中的 `foreach` 循环** - **语法**: ```csharp foreach (类型 变量名 in 集合) { // 处理每个元素 } ``` - **示例**: ```csharp // 遍历数组 int[] numbers = {1, 2, 3}; foreach (int num in numbers) { Console.WriteLine(num); } // 遍历字典 Dictionary<string, int> ages = new Dictionary<string, int> { {"Alice", 30}, {"Bob", 25} }; foreach (KeyValuePair<string, int> entry in ages) { Console.WriteLine($"{entry.Key}: {entry.Value}"); } ``` **注意**:C# 的 `foreach` 要求集合实现 `IEnumerable` 接口,且在循环中不能修改集合元素[^2]。 --- #### 3. **Python 中的 `for` 循环(类似 `foreach`)** - **语法**: ```python for 变量名 in 可迭代对象: # 处理每个元素 ``` - **示例**: ```python # 遍历列表 fruits = ["Apple", "Banana"] for fruit in fruits: print(fruit) # 遍历字典 ages = {"Alice": 30, "Bob": 25} for key, value in ages.items(): print(f"{key}: {value}") ``` --- #### 4. **JavaScript 中的 `forEach` 方法** - **语法**: ```javascript 数组.forEach(function(元素) { // 处理元素 }); ``` - **示例**: ```javascript const numbers = [1, 2, 3]; numbers.forEach(num => { console.log(num); }); ``` **注意**:`forEach` 是数组的方法,无法直接遍历对象,需先转换为数组(如 `Object.keys()`)[^3]。 --- ### **通用注意事项** - **不可修改集合**:多数语言在 `foreach` 遍历时禁止增删集合元素,否则会导致未定义行为或异常。 - **性能差异**:相比传统 `for` 循环,`foreach` 可能因额外迭代器操作稍慢,但可读性更优。 - **适用范围**:适用于顺序遍历,若需索引或复杂控制(如反向遍历),需改用传统循环。
评论 68
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值