序列不包含匹配元素


112

我有一个asp.net应用程序,其中使用linq进行数据操作。运行时,出现异常“序列不包含匹配的元素”。

if (_lstAcl.Documents.Count > 0)
{
    for (i = 0; i <= _lstAcl.Documents.Count - 1; i++)
    {
        string id = _lstAcl.Documents[i].ID.ToString();                           
        var documentRow = _dsACL.Documents.First(o => o.ID == id);
        if (documentRow !=null)
        {

            _lstAcl.Documents[i].Read = documentRow.Read;
            _lstAcl.Documents[i].ReadRule = documentRow.ReadRule;

            _lstAcl.Documents[i].Create= documentRow.Create;
            _lstAcl.Documents[i].CreateRule = documentRow.CreateRule;

            _lstAcl.Documents[i].Update = documentRow.Update;
            _lstAcl.Documents[i].UpdateRule = documentRow.UpdateRule;

            _lstAcl.Documents[i].Delete = documentRow.Delete;
            _lstAcl.Documents[i].DeleteRule = documentRow.DeleteRule;
        }
    }
}

Answers:


220

好吧,我希望这是引发异常的行:

var documentRow = _dsACL.Documents.First(o => o.ID == id)

First()如果找不到任何匹配的元素,将抛出异常。假设您随后要立即测试null,这听起来像是want FirstOrDefault(),如果没有找到匹配项,它将返回元素类型的默认值(对于引用类型为null):

var documentRow = _dsACL.Documents.FirstOrDefault(o => o.ID == id)

在某些情况下要考虑的其他选项是Single()(当您相信只有一个匹配元素时)和SingleOrDefault()(当您相信只有一个或零匹配元素时)。我怀疑这FirstOrDefault是在此特定情况下的最佳选择,但无论如何还是值得了解的。

另一方面,看起来您可能真的会变得更好,首先加入这里。如果您不在乎它会进行所有匹配(而不只是第一个),则可以使用:

var query = from target in _lstAcl.Documents
            join source in _dsAcl.Document
            where source.ID.ToString() equals target.ID
            select new { source, target };
foreach (var pair in query)
{
    target.Read = source.Read;
    target.ReadRule = source.ReadRule;
    // etc
}

这是更简单更高效的IMO。

即使你决定保持环路,我有几个建议:

  • 摆脱外在if。您不需要它,就好像Count为零,for循环体将永远不会执行
  • 在for循环中使用排他上限-在C#中更惯用:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • 消除常见的子表达式:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • 尽可能使用foreach而不是从for以下位置开始:

    foreach (var target in _lstAcl.Documents)

39

使用FirstOrDefault。First永远不会返回null-如果找不到匹配的元素,它将引发您所看到的异常。

_dsACL.Documents.FirstOrDefault(o => o.ID == id);

19
只是稍微说明一下- 如果谓词匹配null值,则First 通常可以返回null。它只是不能在此处返回null,就像o.ID将对null值抛出NullReferenceException一样。
乔恩·斯基特

11

从MSDN库:

First<TSource>(IEnumerable<TSource>)如果source不包含任何元素,则该方法将引发异常。要在源序列为空时返回默认值,请使用FirstOrDefault方法。


0

对于那些通过上下文菜单创建控制器时遇到此问题的人,请以管理员身份重新打开Visual Studio对其进行修复。


-4

也许在First()之前使用Where()可以为您提供帮助,因为在这种情况下,我的问题已得到解决。

var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();

3
实际上在这里帮助您的是使用.FirstOrDefault()而不是.First()-使用.Where(o => o.ID == id).FirstOrDefault()和.FirstOrDefault(o => o.ID == id )将相同。
pwdst

@pwdst使用Where子句中的条件,然后使用FirstOrDefault而不使用任何lambda表达式。
Elnaz
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.