LINQ:异常为“序列不包含任何元素”

20

执行以下 Linq 代码时,我遇到了这个异常:

"Sequence contains no elements"

Linq 代码:

   newGradeRow[rowCnt + 1 + "Grade " + ExamName] = 
      objDataSet.Tables[1].Rows.Cast<DataRow>()
      .Where(p => Convert.ToDecimal(p["EMG_MARKS_ABOVE"]) <= extSubMarks  
         && extSubMarks <= Convert.ToDecimal(p["EMG_MARKS_BELOW"]))
      .Select(p => Convert.ToString(p["EMG_GRADE_NAME"]))
      .First();

有人能帮我解决这个问题吗?


3
异常情况很明显 - 你正在处理的其中一个列表为空,没有返回任何结果。 - Oded
2
正如我在问题中提到的,当执行时,我会得到一个异常,即“序列不包含任何元素”。请问您能告诉我为什么会出现这种异常或者代码有什么问题吗?我是 .net 的新手。 - Sumith Amin
2
我认为你的集合中没有任何项。你认为你应该做什么?这个问题是基本思维练习。 - user47589
12
不确定为什么这个问题被关闭了,它是一个相当基础的问题,但对于将来的linq新手来说,这将是回答这个简单问题的好方法。 - Ben Robinson
3
这个帖子不应该被关闭。我也遇到了同样的异常,但是在其他地方找不到答案。好吧,那我就再问一遍吧 :-) - Arrow
这个问题被错误地关闭了。它很简单,知道在问什么,并且有一个正确的答案和一些赞同(这表明其他人也有同样的疑惑并发现答案有帮助)。也许应该将其标记为重复。https://dev59.com/AnM_5IYBdhLWcg3wjkCr、https://dev59.com/HXNA5IYBdhLWcg3wfN6O、https://dev59.com/pHXYa4cB1Zd3GeqP6Gwe... - Andre Figueiredo
5个回答

51

根据文档所述,如果序列为空,则在First方法调用中会抛出异常。对于这种情况,最好使用FirstOrDefault方法 - 它将返回默认值(在特定情况下为null),不会抛出任何异常。


7

从拆分开始。你现在的代码没有提供给调试器任何把握。

var r1 = objDataSet.Tables[1].Rows;
var r2 = r1.Cast<DataRow>();
System.Diagnostics.Debug.Print("r2: {0}", r2.Count());
var r3 = r2.Where(p => Convert.ToDecimal(p["EMG_MARKS_ABOVE"]) <= extSubMarks  
            && extSubMarks <= Convert.ToDecimal(p["EMG_MARKS_BELOW"]));
System.Diagnostics.Debug.Print("r3: {0}", r3.Count());
var r4 = r3.Select(p => Convert.ToString(p["EMG_GRADE_NAME"]));
var r5 = r4.First();

newGradeRow[rowCnt + 1 + "Grade " + ExamName] = r5;

虽然代码有点繁琐,但很明显唯一可能引发异常的是对First()的调用,它需要1个或多个元素。 - Ben Robinson
@BenRobinson,同意,但是在Where()之前还是之后是空的?我想知道。 - H H
3
好的,但我建议您提及First()函数是会引发异常的,并解释一下First()FirstOrDefault()之间的区别。 - Ben Robinson
我认为Henk的观点是为了调试目的而拆分代码。第1和2行也可能会抛出异常。 - MJ Hufford

3

当你在同一行代码中有许多串联在一起的序列时,很难说哪个序列没有元素。尝试将代码分解为多行,然后进行调试。这将使其更易读。

var myVariable = objDataSet.Tables[1]; 
var myEntity = myVariable.Rows.Cast<DataRow>().Where(
  p => Convert.ToDecimal(p["EMG_MARKS_ABOVE"]) <= extSubMarks
  && extSubMarks <= Convert.ToDecimal(p["EMG_MARKS_BELOW"]))
  .Select(p => Convert.ToString(p["EMG_GRADE_NAME"])).FirstOrDefault();

如果问题出现在Lambda表达式中,您可能需要将其分解为foreach循环(仅出于调试和在VS的即时窗口中访问数据的目的)。


2
你已经将最后一个调用更改为 FirstOrDefault(),这将消除异常,但你没有提到这一点,有点奇怪。 - Ben Robinson
我的错误。我更喜欢使用FirstOrDefault()扩展方法而不是First(),以获得更好的异常处理。然后,在继续之前可以检查是否为空值。 - MJ Hufford

1
你需要注意以下事项: 当 Linq 表达式/查询不包含任何记录时,你不能使用 Single()First()
在 Lambda 表达式中,可以使用 FirstOrDefault() 替换 Single()

0

objDataSet.Tables[1] 是空的吗?

也许数据在 objDataSet.Tables[0] 中?

无论如何,您可以使用 objDataSet.Tables.Count() > 0 进行测试

您可以对行执行相同的操作:objDataSet.Tables[1].Rows.Count() > 0


2
如果没有元素通过Where筛选器,当First被传递一个空列表时,它会引发异常。 - Raymond Chen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接