这是“可能多次枚举IEnumerable”的安全修复

时间:2013-09-23 21:27:30

标签: c#

我目前有这个:

public void Load(IEnumerable<Guid> ids){
    f1(ids);
    f2(ids);
} 

为避免Resharper曲折,建议的修复类似于

public void Load(IEnumerable<Guid> ids){
    var enumerable = ids as IList<Guid> ?? ids.ToList();
    f1(enumerable);
    f2(enumerable);
} 

问题是我永远不会想到“可枚举”的好名字,我不想将其称为idsList或enumeratedIds,并且枚举肯定不起作用,并且ids已经用于参数。所以我的实际问题是这会解决这两个问题吗?

public void Load(IEnumerable<Guid> ids){
    ids = ids as IList<Guid> ?? ids.ToList();
    f1(ids);
    f2(ids);
}

是否存在以上情况会产生意外/效率低下的结果?

2 个答案:

答案 0 :(得分:4)

  

是否存在以上情况会产生意外/效率低下的结果?

如果f1f2都没有列出Guid的整个列表,而ids没有作为List<Guid>提供给您,转换为列表会更昂贵。例如,当f1占用前五个元素时,f2占用FirstOrDefaultids来自非缓存上下文,并包含数千个项目{{1方法的效率会降低。

  

为避免Resharper曲折,建议的修复是......

并非所有Resharper警告都必须修复。该工具会吸引您注意该问题,您可以自行修复或忽略警告。 Resharper一直在寻找潜在的麻烦,但只有你知道ToListf1内发生了什么。如果您认为避免实现列表更有效,请使用f2注释来避免曲线。

答案 1 :(得分:2)

如果您正在使用Entity Framework,其中有执行延迟的实体集合,那么这可能是非常糟糕的事情!想象一下,如果你的ids IEnumerable真的被这样的定义:

var ids = MyDbContext.BillionsOfAccounts.Select(x => x.id);

并且你的函数是这样的(这可能无法编译,但可以解决问题):

public IEnumerable<T> f1(IEnumerable<T> query)
{
  if (query is IQueryable<T>)
  {
    return query.Take(10).ToList();
  }
  return null;
}

public IEnumerable<T> f2(IEnumerable<T> query)
{
  if (query is IQueryable<T>)
  {
    return query.Where(id => (id % 100000000) == 0).ToList();
  }
  return null;
}

如果是这种情况,那么你正在做的事情可能会尝试从数据库而不是预期的10个记录中获取数十亿条记录。

那就是说,很多的情况下你正在尝试的是你想要的。正如其他人所说,你必须根据具体情况处理这个问题。但要回答你的问题,是的,有些情况可能非常坏了!