甚至“IsNullOrEmpty"检查给出了“ienumerable的可能的多个枚举”;警告
本文关键字:枚举 警告 quot IsNullOrEmpty 检查 甚至 ienumerable | 更新日期: 2023-09-27 18:06:57
在SO上已经有一个关于"可能的多个枚举"的问题,但这个问题更具体。
请考虑以下方法,该方法将IEnumerable<string>
作为输入,并对其每个元素执行给定的方法:
public static bool SomeMethod(IEnumerable<string> enumerable)
{
if (enumerable.IsNullOrEmpty())
{
// throw exception.
}
else
{
return (enumerable.All(SomeBooleanMethod));
}
}
在上面的代码中,IsNullOrEmpty
只是一个运行
的扩展方法return (!ReferenceEquals(enumerable, null) || enumerable.Any());
问题是ReSharper警告我"IEnumerable的可能的多个枚举",我真的不知道这是否真的是一个问题。
我理解警告的含义,但是在这种情况下,如果您确实需要检查并抛出null或empty异常,那么您真正可以做什么呢?
这意味着您(部分地)在IEnumerable上迭代不止一次:第一次是在调用Any()
时(至少需要初始化迭代以查看enumerable是否返回任何元素),第二次是在All
中(从开始迭代)。
ReSharper警告你这一点的原因是枚举一个可枚举对象可能会导致副作用,而无意中迭代两次可能会触发两次副作用,这可能是也可能不是我们想要的。
正如@tdammers所指出的,这里所指的"多重枚举"是Any
和All
所需要的两个枚举。因为您想要拒绝空序列,所以我能想到的最好方法是:
public static bool SomeMethod(IEnumerable<string> enumerable)
{
if (enumerable == null)
throw new ArgumentNullException();
// Manually perform an All, keeping track of if there are any elements
bool anyElements = false;
bool result = true;
foreach (string item in enumerable)
{
anyElements = true;
result = result && SomeBooleanMethod(item);
// Can short-circuit here
if (!result)
break;
}
if (!anyElements)
throw new ArgumentException(); // Empty sequence is invalid argument
return result;
}
虽然这里的其他答案都是正确的,因为您枚举了两次(以及这样做的潜在危害),但它们都(微妙地)不正确,因为您为什么会得到警告。
Resharper没有警告你,因为你正在调用Any()
和All()
。它警告你,因为你正在调用IsNullOrEmpty()
和All()
。事实上,Resharper甚至不知道你正在调用Any()
.试着删除它-你会发现你仍然得到警告。
这是因为Resharper 不知道传递给另一个方法的可枚举对象会发生什么。也许其他方法枚举了它,也许没有。但是你将可枚举对象传递给两个方法,所以它们可能都枚举它,所以它可能被枚举两次。因此出现了警告,"可能存在多个枚举"。
这很微妙但很重要。在您的例子中,警告是有用的,因为您的枚举了两次。但是,也许您的扩展方法没有枚举可枚举对象,并且您知道可以忽略警告。在这种情况下,Resharper提供了NoEnumeration
属性在Resharper的代码注释。
这允许你标记一个可枚举对象,就像下面的make up方法:
public static bool IsNull<T>([NoEnumeration]this IEnumerable<T> enumerable)
{
return enumerable is null;
}