我有以下代码,在标题中给出警告。我很确定我以前做过这样的事情,但它没有发出任何警告。我想问一下这些帖子的两件事。 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)
............
可能的问题取决于你的IEnumerable
来自哪里。某些数据源可能只允许单个枚举,或者它们可能很昂贵(可能是某些数据库查询),这些数据源已经由attributeList.Any()
启动。
您可以删除Any()
检查,因为如果IEnumerable
中没有元素,则无论如何都不会运行循环(假设您的示例显示完整的图片,并且没有其他逻辑依赖于检查)。
编辑:根据您编辑的问题,您无法删除支票。但是,您可以使用attributeList.ToArray()
将您的IEnumerable
转换为您随后使用的数组并消除警告。
摆脱if
;这毫无用处。
警告来自Resharper,它警告你,如果attributeList
枚举成本很高,你的代码会很慢。 (因为它列举了一次Any()
和第二次foreach
)
原因是调用attributeList.Any()
从attributeList
开始,一旦发现它进入你的for循环。然后你在列表上做一个foreach,它再次遍历整个列表。
你实际上不需要这里的.Any()
,因为对一个空的可枚举做一个foreach不会导致任何问题,它只是不会返回任何东西。
你可能遇到的问题是,如果你从数据库中提取数据并且在foreach内部再次调用枚举,因为它是延迟执行的,你可能会得到不同的结果,这是你第二次调用时没想到的。
我猜attributeList
是某种类型的IEnumerable<>
。与IEnumerable
s不同,List
对象不一定是内存中对象的列表,并且可能绑定到复杂的逻辑,每次迭代它时都会查询DB。使用C#的yield return
命令也可以返回一个IEnumerable
,它具有与每次迭代绑定的逻辑。
由于此行为,警告会告诉您可能会多次迭代您的属性,这可能是一项可能很昂贵的操作。一次在Any()
期间,一次在foreach
。确实,在这种情况下,Any()
是多余的,但一般来说,您可以通过在ToList()
上调用ToArray()
或IEnumerable
来避免此警告,从而执行枚举一次并将结果存储在显式分配的列表/数组中。现在你可以一次又一次地重复它,没有性能影响。
不,你不需要解决它。但是,如果你的if (attributeList.Any())
没有else
,你可以完全消除它,这将消除警告。实际上,您的代码示例可以替换为:
foreach (AttributeType attribute in attributeList.OfType<AttributeType>())
{
// do stuff
}
你不必检查.Any()这里是固定代码:
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”。
如果attributeList的类型允许,您可以检查Count或Length:
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。