如何使用 LINQ 从泛型列表中获取下一个适当的值

本文关键字:下一个 获取 LINQ 何使用 泛型 列表 | 更新日期: 2023-09-27 18:35:05

我有一个类:

public class CounselPoints
{
    public int CounselNum { get; set; }
    public String CounselPoint { get; set; }
    public bool BR { get; set; }
    public bool ICRVBS { get; set; }
}

。以及该类的通用列表:

List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();

我想从该通用列表中检索下一个合适的 CounselPoint,其中包含可以用 SQL 表示的逻辑,如下所示:

SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint;

我调用此方法来尝试获取该值,并且像这样对它大发雷霆:

public static int GetNextBibleReadingCounselPoint(int LastCounselPoint)
{
    List<CounselPoints> counselPoints = AYttFMConstsAndUtils.DeserializeCounselPointsFile();
    return counselPoints.FirstOrDefault(i => i.CounselNum).Where(j => j.BR).Where(k => k.CounselNum > LastCounselPoint);
}

在"英语"中,我试图说,"给我第一个CounselNum,它比传入的arg(LastCounselPoint)更大,并且BR是正确的"

例如,如果我传入 17,并且 CounselNum val 为 18 的 counselPoint "记录"也将 BR 设置为 true,它应该返回 18。很简单,不是吗?

但是我看似丑陋的,或者充其量是尴尬的尝试,甚至没有编译;我得到:

错误 CS0029 无法将类型"int"隐式转换为"bool"

。和:

错误 CS1662 无法将 lambda 表达式转换为预期的委托类型,因为块中的某些返回类型不能隐式转换为委托返回类型

我不知道为什么它认为我试图转换为布尔值,我绝对不会发现第二个错误。

如果我将代码更改为以下内容:

return counselPoints.FirstOrDefault(i => i.CounselNum > LastCounselPoint).Where(j => j.BR).Select(k => k.CounselNum );

我得到:

错误 CS1061 "CounselPoints"不包含"Where"的定义,并且找不到接受类型为"CounselPoints"的第一个参数的扩展方法"Where"(您是否缺少 using 指令或程序集引用?

。这也只导致我告诉编译器,"除了九个,所有人都下来了,pard;把他们放在另一条巷子里。

解开这个难题的关键是什么?

如何使用 LINQ 从泛型列表中获取下一个适当的值

使用查询时,首先需要使用过滤条件,然后才调用FirstOrDefault

return counselPoints
    .Where(j => j.BR)
    .Where(k => k.CounselNum > LastCounselPoint)
    .Select(i => i.CounselNum)
    .FirstOrDefault();

有两种类型的 LINQ 查询运算符 - 即时查询运算符和延迟查询运算符。 Where是延迟运算符的示例,FirstOrDefault是直接操作者。

在代码中,您在无序列表上使用FirstOrDefault,因此立即筛选了初始列表。

在我提供的示例代码中,我首先使用延迟运算符来定义筛选器,然后才使用即时函数来检索结果。

我在你的例子(以及其他 anwsers 中)看到你写了这样的第一个默认值: .FirstOrDefault(i => i.CounselNum)但我认为你不需要这个。

将第一个默认值视为筛选器而不是选择。

所以相反,你需要这样写

return counselPoints
  .Where(cp => cp.BR && cp.CounselNum > LastCounselPoint)  // where clause
  .Select(cp => cp.CounselNum) // select part
  .FirstOrDefault(); // get top 1 only

*更新>存在

正如@Jannik指出的那样,当没有匹配项时,上述返回零而不是 null。

如果同时测试存在很重要,那么你可以这样写。

CounselPoint cp = counselPoints
  .Where(cp => cp.BR && cp.CounselNum > LastCounselPoint)  // where clause
  .FirstOrDefault(); // get top 1 object of type CounselPoint
if (cp == null)
  return null;
return cp.CounselNum;

请注意,方法的返回类型必须是可为 null 的 int。请参阅下面添加的?

public static int? GetNextBibleReadingCounselPoint(int LastCounselPoint)

。然后我猜你的调用代码来检查结果

int? result = GetNextBibleReadingCounselPoint(lastCounselPoint);
if (result.HasValue) {
  // something was returned
} else {
  // nothing was returned
  int num = result.Value; 
}

*更新2>订单

考虑您的原始 SQL - 我想知道您是否不考虑顺序?

也许您应该通过在底部添加订单:

SELECT TOP 1 CounselNumber
FROM COUNSELPOINTSLU
WHERE BR IS TRUE
AND CounselNumber > @LastCounselPoint
ORDER BY CounselNumber; // ascending

在这种情况下,您可以在 linq 语句中的 where 子句之前添加 order-by;像这样

return counselPoints
  .OrderBy(cp => cp.CounselNum) // order by ascending
  .Where( ... rest of code

我认为dotnetom和Chris Moutray已经回答了这个问题,我只想给一个小的旁注:

下次遇到 LINQ 语句问题时,请尝试将它们拆分为单独的语句。这样做你会看到FirstOrDefault()在 Where() 之前没有任何意义,因为它会返回一个对象,你不能在单个对象上使用 where,对吧?:)

试试这个....

counselPoints
    .Where(j => j.BR && j.CounselNum > LastCounselPoint)
    .FirstOrDefault();