[英]Why does List<T>.ForEach() implement a for loop?
我不明白為什么List<T>.ForEach()
擴展方法實現了一個for
循環。 這開辟了收集被修改的可能性。 正常的foreach
會在這種情況下拋出異常,所以ForEach()
肯定會以同樣的方式做出反應嗎?
如果你因為某種原因必須改變一個集合,那么你肯定應該在for
循環中手動迭代集合嗎?
foreach
和List<T>.ForEach()
之間似乎存在一些語義矛盾。
我錯過了什么嗎?
因為List.ForEach遵循MSDN的定義:
對List的每個元素執行指定的操作。
這意味着對元素執行的Action
可能會更改元素或集合本身 。 在這種情況下,沒有其他方法(如果沒有創建costy克隆集合, 如果可能的話)支付這個,然后使用簡單的for
。
如果在foreach
迭代期間更改集合,它自然會引發異常。
foreach
是一個C#語言元素。 它遵循C#的規則。
List<T>.ForEach
是一種.NET Framework方法。 它遵循.NET的規則,其中foreach
不存在。
這是“語言與框架”混淆的一個例子。 框架方法必須以多種語言工作,並且語言(通常)具有矛盾的語義。
這種“語言與框架”混淆的另一個例子是.net 3和.NET 3.5之間對Enumerable.Cast
的重大改變。 在.NET 3中, Cast
使用了C#語義。 在.net 3.5中,它被改為使用.net語義。
只有BCL團隊的成員可以肯定地告訴我們,但這可能僅僅是List<T>.ForEach
的疏忽List<T>.ForEach
允許您修改列表。
首先,David B的答案對我來說沒有意義。 它是List<T>
,而不是C#,它檢查你是否修改了foreach
循環中的列表,如果你這樣做則拋出InvalidOperationException
。 它與您正在使用的語言無關。
其次, 文檔中有這個警告:
不支持修改Action <T>委托正文中的基礎集合,並導致未定義的行為。
我發現BCL團隊不太可能希望像ForEach
這樣的簡單方法具有未定義的行為。
第三,從.NET 4.5開始, List<T>.ForEach
將在委托修改列表時拋出InvalidOperationException
。 如果程序依賴於舊的行為, 它將在重新編譯為目標.NET 4.5時停止工作 。 微軟願意接受這一突破性變化的事實強烈表明,原始行為是無意的,不應該依賴。
作為參考,這里是List<T>.ForEach
如何在.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);
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.