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

时间:2016-02-18 05:31:44

标签: c# linq generics lambda generic-list

我有一个班级:

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);
}

In&#34;英语,&#34;我试图说,&#34; 给我第一个比传入的arg(LastCounselPoint)更大数量的CounselNum,其中BR是真的&#34;

例如,如果我传入一个17,并且#counselPoint&#34;记录&#34;如果CounselNum值为18也将BR设置为true,则应返回18.简单,不是吗?

但是我显然很可怕,或者至多是尴尬的尝试,甚至无法编译;我明白了:

错误CS0029无法隐式转换类型&#39; int&#39;到&#39; bool&#39;

...和

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

我不知道为什么它认为我试图转换为bool,我绝对不会意识到第二个错误。

如果我将代码更改为:

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

我明白了:

错误CS1061&#39; CounselPoints&#39;不包含&#39; Where&#39;的定义并没有延伸方法&#39;其中&#39;接受第一个类型&#39; CounselPoints&#39;可以找到(你错过了使用指令或汇编引用吗?)

...这也只会导致我告诉编译器,&#34; 所有下来但只有9,pard;设置在另一条小巷上。&#34;

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

4 个答案:

答案 0 :(得分:5)

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

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

有两种类型的LINQ查询运算符 - immediate and deferredWhere是延迟运算符的示例,FirstOrDefault是即时运算符。

在您的代码中,您在无序列表中使用了FirstOrDefault,因此您立即过滤了初始列表。

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

答案 1 :(得分:4)

我在你的例子中(以及其他的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

* update&gt;存在

正如@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;

请注意,方法的返回类型必须是可为空的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; 
}

* update2&gt;为了

考虑原始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

答案 2 :(得分:2)

试试这个......

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

答案 3 :(得分:2)

我认为dotnetom&amp;克里斯·穆特雷已经回答了这个问题,我只是想给出一个小小的注意事项:

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