在 Where<> 查询未命中中的谓词?



我需要为列表中的每个项目调用该方法。因此,我按如下方式使用了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<>,则会触发相同的方法。我不知道这是框架中断还是我走错了路。

作为附加信息,我 using.NET 框架 4.5。

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

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

Where永远不会在当前代码中实际实现(它与您在使用FirstOrDefault时所经历的那样(,因此它永远不会进入CheckName方法。然后,由于Where永远不会返回null而是"最坏情况"一个空集合,这是不null的,结果是true

如果调试,您将看到name等于true。要"克服"这一点,这取决于您想要的输出:

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

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

    var result = list.Where(CheckName);
    

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

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

    如果您只需要结果(从而具体化查询(:

    list.Where(CheckName).ToList();
    

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

  • 林克和延迟执行
  • 在 LINQ 中使用延迟执行有什么好处?

作为旁注,请参阅如何从以下位置更改当前代码:

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

自:

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

并最终:

var name = list.Where(CheckName);

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

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

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

由于Linq 的延迟执行,未执行CheckName()方法。实际语句在您实际访问它之前不会执行。所以在你的情况下,对于CheckName(),你应该做这样的事情:

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

当您查看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;
}
}
}

收益率将导致仅在实际访问返回的IEnumerable<T>后执行。这就是所谓的延迟执行。

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

foreach var name in list
CheckName(name);

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

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

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

这段代码很紧凑,读起来很好;我们可以清楚地看到意图(虽然我不会称列表为"列表" - "名称"会更好(

相关内容

  • 没有找到相关文章

最新更新