可能有多个枚举的 IEnumerable.如何解决?我需要解决吗?
本文关键字:解决 枚举 IEnumerable 何解决 可能有 | 更新日期: 2023-09-27 18:31:56
我有以下代码在标题中给出警告。我很确定我以前做过这样的事情,但它没有给出任何警告。我想问两件事。1)这里什么会导致问题?2)需要修复吗?
我问的原因是这段代码工作正常,因为我希望它能如此清楚地表明此警告不会导致问题。我无法忍受在我的代码中有警告等,所以想要解决这个问题,但我也想知道为什么会发生这种警告以及它是否以任何方式有害。
法典:
public class AttributeType
{
private string m_attributeNameField;
public string AttributeName
{
get { return m_attributeNameField; }
set { m_attributeNameField = value; }
}
}
private StandardResponseType ValidateAttributes(string featureType, IEnumerable<AttributeType> attributeList, string userCategory)
{
StandardResponseType standardResponse =
new StandardResponseType(DateTime.Now.ToString(CultureInfo.InvariantCulture), "RWOL_UTILS.Get_Item_Attributes", "", "OK");
if (attributeList.Any())
{
foreach (AttributeType attribute in attributeList)
{
if (attribute.AttributeName == null) continue;
{
//do stuff
}
}
}
else
{
standardResponse.Message = "Error: No attributes passed in the list. ValidateAttributes().";
standardResponse.ResponseCode = "FAIL";
return standardResponse;
}
}
编辑:该方法中有更多的代码,但它与此问题无关。
更新:我必须添加以下代码才能完成这项工作。为什么添加这个更有效?如果我必须计数并阅读新列表,那么这样做和对原始项目进行计算有什么区别?该列表仅传递一次。如果列表在方法中填充但不是,我可以理解这个问题。它只是通过已经填充。
List<AttributeType> newlist = attributeList.ToList();
if (newlist.Count() != 0)
{
foreach (AttributeType attribute in newlist)
............
去掉if
就行了,没用的。
警告来自 Resharper,它警告您,如果枚举attributeList
成本很高,则代码会很慢。(因为它为Any()
枚举一次,为foreach
枚举第二次)
可能的问题取决于您IEnumerable
的来源。某些数据源可能只允许单个枚举,或者它们可能很昂贵(可能是某些数据库查询),这已经由 attributeList.Any()
启动。
您可以删除Any()
检查,因为如果您的IEnumerable
中没有元素,您的循环无论如何都不会运行(假设您的示例显示了完整的图片,并且没有其他依赖于检查的逻辑)。
:根据您编辑的问题,您无法删除检查。但是,您可以使用attributeList.ToArray()
将IEnumerable
转换为数组,然后使用该数组并摆脱警告。
原因是调用attributeList.Any()
从attributeList
开始,一旦找到某些东西,它就会进入你的 for 循环。 然后,您对列表执行 foreach,该列表再次遍历整个列表。
您实际上不需要这里的.Any()
,因为对空枚举执行 foreach 不会造成任何问题,它只是不会返回任何内容。
您可能会遇到问题的地方是,如果您从数据库中提取数据并在 foreach 内部对枚举进行了另一次调用,因为它是延迟执行,您可能会得到您在第二次调用时没有预料到的不同结果。
我猜attributeList
是某种IEnumerable<>
。 与 List
不同,IEnumerable
对象不一定是内存中的对象列表,并且可能绑定到每次迭代数据库时查询数据库的复杂逻辑。使用 C# 的 yield return
命令还可以返回具有绑定到每次迭代的逻辑的IEnumerable
。
由于此行为,警告会告诉您可能会多次迭代属性,这可能是一项代价高昂的操作。一次在Any()
,一次在foreach
。确实,在这种情况下,Any()
是多余的,但通常您可以通过在IEnumerable
上调用ToList()
或ToArray()
来避免此警告,从而执行一次枚举并将结果存储在显式分配的列表/数组中。现在,您可以一次又一次地检查它,而不会影响性能。
不,你不需要解决它。但是,如果您的if (attributeList.Any())
没有 else
,您可以完全消除它,这将摆脱警告。实际上,您的代码示例可以替换为:
foreach (AttributeType attribute in attributeList.OfType<AttributeType>())
{
// do stuff
}
您不必检查 .任意()这是固定代码:
bool empty = true;
foreach (AttributeType attribute in attributeList)
{
empty = false;
if (attribute.AttributeName == null) continue;
{
//do stuff
}
}
if (empty)
{
{
standardResponse.Message = "Error: No attributes passed in the list. ValidateAttributes().";
standardResponse.ResponseCode = "FAIL";
return standardResponse;
}
}
检查。Any() 会导致枚举,这就是为什么你收到警告 => 第一个枚举"Any"检查它是否为空,第二个枚举"foreach"。
如果属性列表的类型允许,您可以检查 计数 or 长度 :
if (attributeList.Count != 0)
{
foreach (AttributeType attribute in attributeList)
{
if (attribute.AttributeName == null) continue;
{
//do stuff
}
}
}
else
{
standardResponse.Message = "Error: No attributes passed in the list. ValidateAttributes().";
standardResponse.ResponseCode = "FAIL";
return standardResponse;
}
我能够允许你这样做,它更漂亮:
但无论如何,当你打电话.Any() 它只迭代第一项,所以它真的没有那么糟糕。
这种方式只是更具可读性,尽管在后台有点丑陋(仍然有效)。
bool any;
foreach (var i in Enumerable.Range(0, 100).Loop(out any))
{
// Do loop logic
}
if (!any)
{
// Handle empty IEnumerable
}
如何?!:
public static class Ex
{
public static IEnumerable<T> Loop<T>(this IEnumerable<T> source, out bool any)
{
var b = true;
var enumerable = source.Loop(() => { b = false; });
any = b;
return enumerable;
}
private static IEnumerable<T> Loop<T>(this IEnumerable<T> source, Action anySetter)
{
var enumerator = source.GetEnumerator();
enumerator.Reset();
if (!enumerator.MoveNext())
{
anySetter();
yield break;
}
do
{
yield return enumerator.Current;
} while (enumerator.MoveNext());
}
}
由于我为数据集的查询搜索了这个确切的问题,所以我去添加.Any() 并发现我可以添加 .AsQueryable() 到我的选择结束,我的 foreach 使用它。.AsQueryable 将通用 IEnumerable 转换为通用 IQueryable。