Послідовність не містить відповідного елемента


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;
        }
    }
}

Відповіді:


220

Ну, я б очікував, що виняток кидає саме ця лінія:

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
}

Це простіше та ефективніше ІМО.

Навіть якщо ви дійсно вирішили зберегти цикл, у мене є кілька пропозицій:

  • Позбавтеся від зовнішнього if. Вам це не потрібно, як якщо б число не дорівнює, тіло циклу ніколи не виконається
  • Використовуйте ексклюзивні верхні межі для циклів - вони більш ідіоматичні в 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 . Перший ніколи не поверне null - якщо він не може знайти відповідний елемент, він викидає той виняток, який ви бачите.

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

19
Просто для уточнення - спочатку можна повернути нуль взагалі, якщо ваш предикат збігається з нульовими значеннями. Він просто не може повернути нуль сюди, як o.IDби викинув NullReferenceException на нульове значення.
Джон Скіт

11

З бібліотеки MSDN:

First<TSource>(IEnumerable<TSource>)Метод генерує виняток , якщо джерело не містить елементів. Щоб замість цього повернути значення за замовчуванням, коли послідовність джерела порожня, використовуйте FirstOrDefaultметод.


0

Для тих із вас, хто зіткнувся з цією проблемою під час створення контролера через контекстне меню, повторно відкривши Visual Studio як адміністратор виправив його.


-4

Можливо, використання Where () до First () може допомогти вам, оскільки моя проблема була вирішена в цьому випадку.

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 без будь-якого лямбда-виразу.
Елназ
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.