foreach和list.ForEach的區別


平時寫代碼的時候要對一個List<T>進行遍歷操作時,經常會糾結是要用foreach還是使用.ForEach方法。現在來搞清楚這二者之間的使用區別和性能上的差異。

一、使用

1.在foreach和list.ForEach中使用list.Remove()

在foreach中是不能使用list.Remove(),否則在進入下一個循環就會報異常,所以,如果有使用之后就必須break;

在.ForEach()中,要注意,在.net framework 4.5 會報異常:集合已修改;可能無法執行枚舉操作。在.net framework4 3.5 3.0 2.0這幾個版本下,可以直接使用list.Remove(),但如果在使用Remove()后下一項是不會遍歷到,會自動用下下項。如下代碼

 

 1         List<Person> list = new List<Person>(){
 2             new Person(){ Id=1,Name="1"},
 3             new Person(){ Id=2,Name="2"},
 4             new Person(){ Id=3,Name="3"},
 5             new Person(){ Id=4,Name="4"},
 6             };
 7             list.ForEach(item =>
 8             {
 9                 Console.WriteLine(string.Format("111--Id:{0},Name:{1}", item.Id, item.Name));
10                 if (item.Id == 2)
11                 {
12                     list.Remove(item);
13                     item.Id = item.Id * 10;
14                 }
15                 item.Id = item.Id * 10;
16                 Console.WriteLine(string.Format("222--Id:{0},Name:{1}", item.Id, item.Name));
17             });
18             Console.WriteLine("------------");
19             list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));    
View Code

結果:

111--Id:1,Name:1
222--Id:10,Name:1
111--Id:2,Name:2
222--Id:200,Name:2
111--Id:4,Name:4
222--Id:40,Name:4
------------
Id:10,Name:1
Id:3,Name:3
Id:40,Name:4

就是在id=2這項remove后還會對這項進行操作,但在進入下一項是id=4,而id=3這項沒有遍歷到

所以如果想刪除id=2和id=3這兩項,結果是id=3是刪除不了,如下:

1     list.ForEach(item =>
2             {
3                 if (item.Id == 2 || item.Id==3)
4                 {
5                     list.Remove(item);
6                 }
7             });
8             list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));    
View Code

結果:

Id:1,Name:1
Id:3,Name:3
Id:4,Name:4

只刪除了id=2這項,所以想刪除list中的項,最好還是用for

1     for (int i = 0; i < list.Count; i++)
2             {
3                 if (list[i].Id == 2 || list[i].Id == 3)
4                 {
5                     list.Remove(list[i]);                    
6                     i--;
7                 }
8             }
View Code

注意刪除后,i--;

或者使用list.RemoveAll(),如下:

1             list.RemoveAll(item => { return item.Id == 2 || item.Id == 3; });
2             list.ForEach(item => Console.WriteLine(string.Format("Id:{0},Name:{1}", item.Id, item.Name)));
View Code

所以,想刪除list中的項,最好不用使用foreach和list.ForEach,而是使用for或list.RemoveAll

2.在list.ForEach()中不能使用continue或者break

如果在遍歷到某個特殊項的時候,不用遍歷后面的項,需要break,這種情況使用foreach

3.list.ForEach()的使用

foreach的使用就不說了。

看一下msdn上對list.ForEach的參數的說明:

System.Action<T>
要對 List<T> 的每個元素執行的 Action<T> 委托。

Action<T> 是對傳遞給它的對象執行某個操作的方法的委托。當前 List<T> 的元素被分別傳遞給 Action<T> 委托。msdn上的示例代碼:

 1 using System;
 2 using System.Collections.Generic;
 3 
 4 class Program
 5 {
 6     static void Main()
 7     {
 8         List<String> names = new List<String>();
 9         names.Add("Bruce");
10         names.Add("Alfred");
11         names.Add("Tim");
12         names.Add("Richard");
13 
14         // Display the contents of the list using the Print method.
15         names.ForEach(Print);
16 
17         // The following demonstrates the anonymous method feature of C#
18         // to display the contents of the list to the console.
19         names.ForEach(delegate(String name)
20         {
21             Console.WriteLine(name);
22         });
23     }
24 
25     private static void Print(string s)
26     {
27         Console.WriteLine(s);
28     }
29 }
View Code

所以,如果有需要用到委托方法,可以使用list.ForEach

平時使用list.ForEach一般都是用Lambda 表達式

二、性能

簡單寫了一個測試代碼,循環一千萬次,看下所用時間:

 1             List<Person> list = new List<Person>();
 2             for (int i = 0; i < 10000000; i++)
 3             {
 4                 list.Add(new Person() { Id = i, Name = i.ToString() });
 5             }
 6             Stopwatch watch = new Stopwatch();
 7             watch.Start();
 8             foreach (var item in list)
 9             {
10                 item.Id = item.Id + 1;
11             }
12             watch.Stop();
13             Console.WriteLine(string.Format("foreach執行時間:{0}", watch.Elapsed));            
14             watch = new Stopwatch();
15             watch.Start();
16             list.ForEach(item => { item.Id = item.Id + 1; });
17             watch.Stop();
18             Console.WriteLine(string.Format("list.ForEach執行時間:{0}", watch.Elapsed));
19             watch = new Stopwatch();
20             watch.Start();
21             for (int i = 0; i < list.Count; i++)
22             {
23                 list[i].Id = list[i].Id + 1;
24             }
25             watch.Stop();
26             Console.WriteLine(string.Format("for1執行時間:{0}", watch.Elapsed));
27             watch = new Stopwatch();
28             watch.Start();
29             int count = list.Count;
30             for (int i = 0; i < count; i++)
31             {
32                 list[i].Id = list[i].Id + 1;
33             }
34             watch.Stop();
35             Console.WriteLine(string.Format("for2執行時間:{0}", watch.Elapsed));
View Code

結果:

foreach執行時間:00:00:00.2760314
list.ForEach執行時間:00:00:00.2458242
for1執行時間:00:00:00.3641918
for2執行時間:00:00:00.1642685

效率最高是for2,for1和for2區別看代碼就知道了,list.ForEach會比foreach略快一點,但差別並不大,所以在使用foreach和list.ForEach上可以不考慮性能上的差異。

總結,foreach和list.ForEach在性能上差異不大,在使用上實際也不會有很多差別,只是在幾個特殊使用上會有所不同,但list.ForEach代碼看上去會更新簡潔一些。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM