为什么列出<;T>;.ForEach在循环结束后检查版本
本文关键字:结束 循环 版本 检查 gt lt 为什么 ForEach | 更新日期: 2023-09-27 18:28:57
我们查看了List.ForEach方法的源代码,它的实现如下:
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);
}
我们找不到版本被检查两次的原因。我们认为可以抛出该异常而不是break
。我们还认为,如果在循环完成后,在执行检查之前,另一个线程修改了列表,那么最终检查可能会导致不必要的异常。
简单地说,为什么循环不是这样实现的:
for(int i = 0 ; i < _size; i++) {
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5) {
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
action(_items[i]);
}
检查本质上验证对操作委托的最后一次调用不会更改集合。
由于这是合同的一部分,根据文件中的备注:
不支持修改Action委托主体中的基础集合,这会导致未定义的行为。
那么这是完全合法的,也是正确的做法
此外,他们推迟了将异常从循环内部抛出到循环后的代码,以避免重复有意义的代码。
话虽如此,代码可能是这样写的:
for (int i = 0 ; i < _size; i++)
{
action(_items[i]);
if (version != _version && BinaryCompatibility.TargetsAtLeast_Desktop_V4_5)
ThrowHelper.ThrowInvalidOperationException(ExceptionResource.InvalidOperation_EnumFailedVersion);
}
代码的当前外观可能是由于反编译或类似操作复制了if部分,而不是对ThrowHelper的调用。