代码检查:可能的多次枚举
请考虑以下代码片段:
IEnumerable<string> names = GetNames();
foreach (var name in names)
Console.WriteLine("Found " + name);
var allNames = new StringBuilder();
foreach (var name in names)
allNames.Append(name + " ");
假设 GetNames() 返回一个 IEnumerable<string> ,我们实际上通过在两个 foreach 语句中枚举此集合两次而做了额外的工作。
如果 GetNames() 导致数据库查询,情况可能会变得更糟,在这种情况下,如果某些其他进程在两次调用之间更改了数据库,您可能会在两个 foreach 循环中得到不同的值。
这种问题可以很容易地解决——通过将序列转换为数组或列表来强制在变量初始化时进行枚举,例如:
List<string> names = GetNames().ToList();
您的其余代码可以保持不变,因为数组和列表类型都实现了 IEnumerable 接口。
误报
有时,如果 IEnumerable 对象在被枚举之前被传递给某个方法,此检查可能会产生误报。 例如:
public void Foo(IEnumerable<string> values)
{
ThrowIfNull(values, nameof(values));
var x = values.ToList(); // Possible multiple enumeration of IEnumerable
}
public static void ThrowIfNull<T>(T value, string name) where T : class
{
// custom check for null but no enumeration
}
在这种情况下,JetBrains Rider 假定该方法将进行额外的枚举,这在大多数情况下是正确的。 如果该方法实际上并未枚举 IEnumerable 对象,您可以使用 [NoEnumerationAttribute]标记相应的参数以防止误报:
public void Foo(IEnumerable<string> values)
{
ThrowIfNull(values, nameof(values));
var x = values.ToList(); // No warnings about multiple enumeration
}
public static void ThrowIfNull<T>([NoEnumeration] T value, string name) where T : class
{
// custom check for null but no enumeration
}
最后修改日期: 2025年 9月 26日