Последовательность не содержит соответствующего элемента - PullRequest
98 голосов
/ 22 октября 2010

У меня есть приложение 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;
        }
    }
}

Ответы [ 5 ]

195 голосов
/ 22 октября 2010

Что ж, я ожидаю, что именно эта строка вызывает исключение:

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

First() сгенерирует исключение, если не найдет подходящих элементов.Учитывая, что вы тестируете на null сразу после этого, звучит так, как будто вы хотите FirstOrDefault(), который возвращает значение по умолчанию для типа элемента (которое является нулевым для ссылочных типов), если не найдено подходящих элементов:

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 никогда не выполнится
  • Используйте эксклюзивные верхние границы для циклов - они более идиоматичны в 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)
    
31 голосов
/ 22 октября 2010

Использовать FirstOrDefault . First никогда не вернет null - если он не может найти соответствующий элемент, он выдает исключение, которое вы видите.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);
10 голосов
/ 22 октября 2010

из библиотеки MSDN: Метод First (IEnumerable) выдает исключение, если источник не содержит элементов. Чтобы вместо этого возвратить значение по умолчанию, когда исходная последовательность пуста, используйте метод FirstOrDefault

0 голосов
/ 20 марта 2019

Для тех из вас, кто сталкивался с этой проблемой при создании контроллера с помощью контекстного меню, повторное открытие Visual Studio в качестве администратора исправило ее.

0 голосов
/ 14 августа 2016

Возможно, использование Where () перед First () может помочь вам, так как моя проблема в этом случае решена.

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