0

我需要为列表中的每个项目调用该方法。所以,我使用Where<>了如下查询,

List<string> list = new List<string>();
list.Add("Name1");
list.Add("Name2");
list.Add("Name3");

var name = list.Where(n =>
{
    return CheckName(n);
});

但在上述情况下,CheckName()是没有命中的。如果我使用FirstOrDefault<>. 我不知道这是框架中断还是我走错了路。

作为附加信息,我使用的是 .NET Framework 4.5。

有没有人遇到过这个错误?如果是这样,是否有任何解决方案来克服这个问题?

4

5 回答 5

3

您错误地理解了Where条件的结果。由于 linq 被延迟执行,它只会在具体化时进入 where 条件(通过ToList/ FirstOrDefault/Sum等)。

从未在您当前的Where代码中实际实现(它就像您在使用时所经历的那样FirstOrDefault),因此它永远不会进入该CheckName方法。然后, asWhere永远不会返回null,而是“最坏情况”一个空集合,不是null,结果是true

如果你调试,你会在最后看到nameequals true。要“克服”这取决于您想要的输出是什么:

  1. 如果您想知道是否有任何与谓词匹配的项目,那么:

    var result = list.Any(CheckName);
    
  2. 如果要检索与谓词匹配的那些:

    var result = list.Where(CheckName);
    

    如果稍后您想查询并检查是否results包含任何内容,则:

    if(result.Any()) { /* ... */ }
    

    如果您只想要结果(从而实现查询):

    list.Where(CheckName).ToList();
    

在此处阅读有关延迟执行的 linq 的更多信息:


就像旁注一样,看看如何从以下位置更改当前代码:

var name = list.Where(n =>
{
    return CheckName(n);
})

至:

var name = list.Where(n => CheckName(n));

并最终:

var name = list.Where(CheckName);
于 2017-07-06T06:18:37.070 回答
2

LINQ 有一个延迟执行主体,这意味着除非您访问name变量,否则查询不会被执行。如果您想立即执行它,(例如).ToList()在最后添加,这正是这样FirstOrDefault做的。它立即执行而不是延迟执行。

var name = list.Where(n =>
{
    return CheckName(n);
}).ToList() != null;

条件结果也where永远不会null。即使没有list满足您的条件的对象CheckNamewhere也会返回一个空集合。

于 2017-07-06T06:21:28.377 回答
1

由于 Linq 的延迟执行,该CheckName()方法未执行。在您实际访问它之前,不会执行实际的语句。因此,在您的情况下,对于CheckName(),您应该执行以下操作:

var name = list.Where(n =>
{
    return CheckName(n);
}).ToList();
于 2017-07-06T06:32:48.317 回答
0

当您查看Where-Method代码时,您可以轻松了解原因:

    internal static IEnumerable<T> Where<T>(this IEnumerable<T> enumerable, Func<T, bool> where) {
        foreach (T t in enumerable) {
            if (where(t)) {
                yield return t;
            }
        }
    }

yield 将导致执行仅在IEnumerable<T>实际访问返回时发生。这就是所谓的延迟执行。

于 2017-07-06T06:36:22.140 回答
0

如果您需要为列表中的每个项目调用一个方法,那么您应该使用一个简单的 for 循环:

foreach var name in list
  CheckName(name);

仅仅因为 LINQ 可用,并不意味着它应该在任何有集合的地方使用。编写有意义且自我注释的代码很重要,在这里使用它同时在您的逻辑中引入了一个缺陷,并使您的代码更难阅读、理解和维护。这是用于所述目的的错误工具

毫无疑问,您还有其他未在此处说明的要求,例如“我想检查列表中的每个名称并确保没有一个为空”。您可以并且可能应该为此使用 linq,但它看起来更像

bool allNamesOK = list.All(n => n != null);

这段代码很紧凑,可读性很好;我们可以清楚地看到意图(尽管我不会将列表称为“列表”-“名称”会更好)

于 2017-07-06T06:34:03.107 回答