我有一个班级:
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;
解开这个难题的关键是什么?
答案 0 :(得分:5)
使用查询时,首先需要使用过滤条件,然后才调用FirstOrDefault
:
return counselPoints
.Where(j => j.BR)
.Where(k => k.CounselNum > LastCounselPoint)
.Select(i => i.CounselNum)
.FirstOrDefault();
有两种类型的LINQ查询运算符 - immediate and deferred。 Where
是延迟运算符的示例,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
正如@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;
}
考虑原始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()之前没有任何意义,因为它会返回一个对象而你不能在一个对象上使用,对吧? :)