我不明白为什么 List<T>.ForEach()
扩展方法实现了一个 for
在引擎盖下循环。这打开了修改集合的可能性。正常 foreach
在这种情况下肯定会抛出异常 ForEach()
应该以同样的方式使用react吗?
如果您出于任何原因必须改变一个集合,那么您肯定应该手动迭代 for
中的集合循环?
foreach
之间似乎有一点语义上的矛盾。和 List<T>.ForEach()
.
我错过了什么吗?
最佳答案
只有 BCL 团队的一名成员可以肯定地告诉我们,但这可能只是一个疏忽 List<T>.ForEach
允许您修改列表。
首先,David B 的回答对我来说没有意义。这是List<T>
,而不是 C#,它会检查您是否修改了 foreach
中的列表循环并抛出 InvalidOperationException
如果你这样做。这与您使用的语言无关。
其次,documentation 中有这个警告:
Modifying the underlying collection in the body of the Action<T> delegate is not supported and causes undefined behavior.
我发现 BCL 团队不太可能想要像 ForEach
这样简单的方法有未定义的行为。
第三,从 .NET 4.5 开始,List<T>.ForEach
将抛出 InvalidOperationException
如果代表修改列表。如果程序依赖于旧行为,it will stop working当它被重新编译为目标 .NET 4.5 时。 Microsoft 愿意接受这一重大更改这一事实强烈表明原始行为是无意的,不应依赖。
作为引用,这里是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);
}
关于c# - 为什么 List<T>.ForEach() 实现 for 循环?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11493330/