我不明白爲什麼List<T>.ForEach()
擴展方法在底層實現for
循環。這打開了修改集合的可能性。正常的foreach
會在這種情況下拋出異常,所以ForEach()
應該以相同的方式反應?爲什麼列表<T> .ForEach()實現for循環?
如果你不管出於什麼原因都必須改變一個集合,那麼你肯定應該手動迭代for
循環中的集合呢?
foreach
和List<T>.ForEach()
之間似乎有點語義上的矛盾。
我錯過了什麼嗎?
我不明白爲什麼List<T>.ForEach()
擴展方法在底層實現for
循環。這打開了修改集合的可能性。正常的foreach
會在這種情況下拋出異常,所以ForEach()
應該以相同的方式反應?爲什麼列表<T> .ForEach()實現for循環?
如果你不管出於什麼原因都必須改變一個集合,那麼你肯定應該手動迭代for
循環中的集合呢?
foreach
和List<T>.ForEach()
之間似乎有點語義上的矛盾。
我錯過了什麼嗎?
只有BCL團隊的成員可以肯定地告訴我們,但可能只是一個疏忽,您可以修改列表。
首先,David B的回答對我沒有意義。它是List<T>
而不是C#,用於檢查您是否修改foreach
循環內的列表,如果您這樣做則拋出InvalidOperationException
。它與您使用的語言無關。
其次,有此警告在documentation:
修改底層集合中的不支持此操作<牛逼>委託的身體,並導致不確定的行爲。
我發現BCL團隊不太可能想要像ForEach
這樣的簡單方法有未定義的行爲。
第三,自.NET 4.5起, 將如果委託人修改列表,則會拋出InvalidOperationException
。如果一個程序依賴於舊的行爲,當它被重新編譯爲目標.NET 4.5時,該程序就是it will stop working。微軟願意接受這一重大變化的事實強烈表明,原來的行爲是無意的,不應該依賴。
以供參考,在這裏是如何實現在.NET 4.0中,直接從參考源:
public void ForEach(Action<T> action) {
if(action == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
Contract.EndContractBlock();
for(int i = 0 ; i < _size; i++) {
action(_items[i]);
}
}
而這裏的它是如何被改變了.NET 4.5:
public void ForEach(Action<T> action) {
if(action == null) {
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
Contract.EndContractBlock();
int version = _version;
for(int i = 0 ; i < _size; i++) {
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) {
break;
}
action(_items[i]);
}
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
可能的性能原因呢? – nawfal 2013-05-30 13:39:04
@nawfal:可能不是。檢查'if(version!= _version)'的代價是不太可能測量的。 – 2013-05-30 17:51:34
List.ForEach由於從MSDN定義以下:
執行列表中的每個元件上的指定的操作。
這意味着,在該元件執行Action
,可以潛在地改變元件,或集合本身。在這種情況下,沒有其他辦法(如果不創建費錢的克隆集合,如果有可能)提供這個,然後使用簡單的for
。
如果您在迭代過程中更改了集合foreach
,它自然會引發異常。
啊,根據定義它是正確的。我仍然覺得這有點誤導。我想這就是所有爭議的原因(以及他們從.NET地鐵中放棄它的原因,正如BoltClock指出的那樣)? – davenewza 2012-07-15 16:06:56
@davenewza不,鏈接的文檔說_Modificare la raccolta sottostante nel corpo di'Action
foreach
是一個C#語言元素。它遵循C#的規則。
是一個.NET Framework方法。它通過.NET的規則進行播放,其中foreach
不存在。
這是一個「語言vs框架」混淆的例子。框架方法必須以多種語言工作,並且語言(通常)具有矛盾的語義。
這種「語言vs框架」混淆的另一個例子是在.net 3和.NET 3.5之間對Enumerable.Cast
的重大改變。在.NET 3中,Cast
使用了C#語義。在.net 3.5中,它被改爲使用.net語義。
「這將打開增加收藏被修改的可能性。「 [確切地說,爲什麼它現在從.NET for Metro風格的應用程序中消失了。](http://stackoverflow.com/questions/10299458/is-the-listt-foreach-extension-method-gone/10299492#10299492)何哼。 – BoltClock 2012-07-15 15:56:03
Eric Lippert(不贊成)[對'.ForEach'的評論](http://blogs.msdn.com/b/ericlippert/archive/2009/05/18/foreach-vs-foreach.aspx)總是值得一讀在這方面。 – 2012-07-15 16:10:45
順便說一句:http://stackoverflow.com/questions/10299458/is-the-listt-foreach-extension-method-gone – user287107 2012-07-15 16:23:44