尝试创建排序方法时,可能会对IEnumerable进行多次枚举

3

我创建了3个方法:

public IOrderedEnumerable<JObject> SortByImportance(IOrderedEnumerable<JObject> products)
{
    if (products == null) throw new ArgumentNullException(nameof(products));

    var firstProduct = products.First();
    return !firstProduct.ContainsKey("importance") ? 
        products : 
        products.OrderByDescending(m => m["importance"]);
}

public async Task<IOrderedEnumerable<JObject>> SortByPriorityAsync(string categoryId, IOrderedEnumerable<JObject> products, List<Answer> answers)
{
    if (string.IsNullOrEmpty(categoryId)) throw new ArgumentNullException(nameof(categoryId));
    if (products == null) throw new ArgumentNullException(nameof(products));
    if (answers == null) throw new ArgumentNullException(nameof(answers));

    var questions = await _questionProvider.Value.ListAsync(categoryId);
    if (questions == null) throw new ArgumentNullException(nameof(questions));
    if (questions.Count == 0) throw new ArgumentException(nameof(questions));

    foreach (var answer in answers)
        answer.Question = questions.SingleOrDefault(m => m.Id == answer.QuestionId);

    var sortedAnswers = answers.OrderBy(m => m.Question.Priority);
    return sortedAnswers.Aggregate(products, (current, answer) => current.ThenByDescending(m => m[answer.Question.Text.ToLower()].ToString().Equals(answer.Text, StringComparison.OrdinalIgnoreCase)));
}

public async Task<IOrderedEnumerable<JObject>> SortBySortationAsync(string categoryId, IOrderedEnumerable<JObject> products)
{
    if (string.IsNullOrEmpty(categoryId)) throw new ArgumentNullException(nameof(categoryId));
    if (products == null) throw new ArgumentNullException(nameof(products));

    var sortations = await _sortationProvider.Value.ListAsync(categoryId);
    if (sortations == null) throw new ArgumentNullException(nameof(sortations));
    if (sortations.Count == 0) throw new ArgumentException(nameof(sortations));

    var orderedSortations = sortations.OrderBy(m => m.Order);

    return orderedSortations.Aggregate(products, (current, sortation) => current.ThenByDescending(m => m[sortation.Field].ToString().Equals(sortation.Expression)));
}

这三种方法可以按顺序调用,以改变产品列表的顺序。例如:

var orderedProducts = products.OrderBy(a => 1);
orderedProducts = await sortProvider.SortBySortationAsync(categoryId, orderedProducts);
orderedProducts = await sortProvider.SortByPriorityAsync(categoryId, orderedProducts, answers);
orderedProducts = sortProvider.SortByImportance(orderedProducts);

这段代码运行正常,我的单元测试显示排序正常,但在 SortByImportance 方法中,它报告:

可能会多次枚举 IEnumerable

出现在 products.First() 调用中。 有人能告诉我如何解决这个问题吗?


1
你可以将你的集合转换为ToList()一次,从而避免这个警告。 - PiJei
如果我这样做,我就不能使用我的方法,因为它们使用ThenBy而不是OrderBy来维护先前的顺序。 - r3plica
"如果firstProduct包含“importance”,则返回products按照m [“importance”]降序排列的结果,否则返回products;" 更易于阅读。" - user82593
1
这并不是一个“可能”的多次枚举;你正在多次枚举它... - Marc Gravell
2个回答

0
如果这是期望的行为,您可以通过适当的注释来抑制警告。
或者,您可以使用一个技巧:
var orderedProducts = products.OrderBy(a => 1) 
                       .ToList() // do the sorting
                       .OrderBy(a => 1); //convert to IOrderedEnumerable

警告仍然存在,但第二个排序将是排序的最佳方案,从而只需将IEnumerable转换为IOrderedEnumerable(可能只需一次枚举)。


0
尝试使用代码:var firstProduct = products.ToList().First();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接