可能有多个枚举的 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)
............

可能有多个枚举的 IEnumerable.如何解决?我需要解决吗?

去掉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。