3

我有以下代码在标题中给出警告。我很确定我以前做过这样的事情,但它没有给出任何警告。我想问那些张贴的两件事。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)
............
4

8 回答 8

6

只需摆脱if; 没用的。

警告来自 Resharper,它警告您如果attributeList枚举成本很高,您的代码将会很慢。(因为它为 the 枚举了一次,为 the 枚举Any()了第二次foreach

于 2012-04-23T12:49:08.887 回答
3

可能的问题取决于您IEnumerable来自哪里。一些数据源可能只允许单个枚举,或者它们可能很昂贵(可能是一些数据库查询),这已经由attributeList.Any().

您可以删除Any()检查,因为如果您的 没有元素IEnumerable,则您的循环无论如何都不会运行(假设您的示例显示了完整的图片并且没有其他依赖于检查的逻辑)。

编辑:根据您编辑的问题,您无法删除检查。但是,您可以使用attributeList.ToArray()将您的数组转换IEnumerable为数组,然后使用该数组并消除警告。

于 2012-04-23T12:50:51.283 回答
1

原因是那个调用attributeList.Any()开始了attributeList,一旦找到它就会进入你的 for 循环。然后你在列表上做一个 foreach ,它再次遍历整个列表。

您实际上不需要.Any()这里,因为对空的枚举执行 foreach 不会导致任何问题,它不会返回任何内容。

您可能会遇到问题的地方是,如果您从数据库中提取数据并且在 foreach 内部再次调用枚举,因为它是延迟执行,您可能会得到不同的结果,这是您在第二次调用时没有预料到的。

于 2012-04-23T12:50:54.783 回答
1

我猜attributeListIEnumerable<>某种。IEnumerableLists 不同,对象不一定是内存中的对象列表,并且可能会绑定到复杂的逻辑,每次迭代时都会为它们查询数据库。使用 C# 的yield return命令还可以返回一个IEnumerable逻辑绑定到每个迭代的。

由于这种行为,警告会告诉您您可能不止一次地迭代您的属性,这是一个潜在的昂贵操作。一次期间Any(),一次结束foreach。确实在这种情况下Any()是多余的,但通常您可以通过调用ToList()orToArray()来避免此警告IEnumerable,从而执行一次枚举并将结果存储在显式分配的列表/数组中。现在您可以一次又一次地检查它,而不会影响性能。

于 2012-04-23T12:54:09.337 回答
0

我能够允许你这样做,它更漂亮:

但无论如何,当你调用 .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());
    }
}
于 2012-04-23T13:14:38.920 回答
0

您不必检查 .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;         
    } 
于 2012-04-23T12:49:53.817 回答
0

不,你不需要解决它。但是,如果您if (attributeList.Any())没有else,则可以完全消除它,这将消除警告。实际上,您的代码示例可以替换为:

foreach (AttributeType attribute in attributeList.OfType<AttributeType>())
{
    // do stuff
}
于 2012-04-23T12:50:42.263 回答
0

由于我为我的数据集查询搜索了这个确切的问题,我去添加 .Any() 并发现我可以将 .AsQueryable() 添加到我的选择末尾并且我的 foreach 可以使用它。.AsQueryable 将通用 IEnumerable 转换为通用 IQueryable。

于 2019-03-12T23:59:17.913 回答