序列不包含匹配的元素

我有一个 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;
}
}
}
280421 次浏览

使用 FirstOrDefault。First 永远不会返回 null-如果它找不到匹配的元素,它会抛出你看到的异常。

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

好吧,我想是这句台词抛出了异常:

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

如果找不到任何匹配的元素,First() 将引发异常。考虑到之后立即测试 null,这听起来像是您想要 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++)
    
  • Eliminate common subexpressions:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
    
  • Where possible use foreach instead of for to start with:

    foreach (var target in _lstAcl.Documents)
    

来自 MSDN 库:

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

也许使用 Where () before First ()可以帮助您,因为我的问题已经在本例中得到了解决。

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

对于那些在通过上下文菜单创建控制器时遇到此问题的用户,请作为管理员修复重新打开 VisualStudio。