Urutan tidak berisi elemen yang cocok

112

Saya memiliki aplikasi asp.net di mana saya menggunakan LINQ untuk manipulasi data. Saat berjalan, saya mendapatkan pengecualian "Urutan tidak berisi elemen yang cocok".

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

Jawaban:

220

Nah, saya berharap baris inilah yang memberikan pengecualian:

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

First()akan mengeluarkan pengecualian jika tidak dapat menemukan elemen yang cocok. Mengingat Anda sedang menguji null segera setelahnya, sepertinya Anda menginginkannya FirstOrDefault(), yang mengembalikan nilai default untuk jenis elemen (yang null untuk jenis referensi) jika tidak ada item yang cocok ditemukan:

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

Opsi lain yang perlu dipertimbangkan dalam beberapa situasi adalah Single()(jika Anda yakin hanya ada satu elemen yang cocok) dan SingleOrDefault()(jika Anda yakin hanya ada satu atau nol elemen yang cocok). Saya curiga itu FirstOrDefaultadalah opsi terbaik dalam kasus khusus ini, tetapi perlu diketahui tentang yang lain.

Di sisi lain, sepertinya Anda akan lebih baik jika bergabung di sini sejak awal. Jika Anda tidak peduli bahwa itu akan melakukan semua pertandingan (bukan hanya yang pertama) Anda dapat menggunakan:

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
}

Itu IMO yang lebih sederhana dan lebih efisien.

Bahkan jika Anda tidak memutuskan untuk menjaga loop, saya memiliki beberapa saran:

  • Singkirkan bagian luarnya if. Anda tidak membutuhkannya, seolah-olah Hitungan nol, badan perulangan for tidak akan pernah dieksekusi
  • Gunakan batas atas eksklusif untuk loop - mereka lebih idiomatis di C #:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Hilangkan subekspresi umum:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Jika memungkinkan, gunakan foreachdaripada formemulai dengan:

    foreach (var target in _lstAcl.Documents)
Jon Skeet
sumber
39

Gunakan FirstOrDefault . Pertama tidak akan pernah mengembalikan null - jika tidak dapat menemukan elemen yang cocok, ia akan menampilkan pengecualian yang Anda lihat.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);
Jakub Konecki
sumber
19
Hanya untuk memperjelas sedikit - Pertama dapat mengembalikan null secara umum, jika predikat Anda cocok dengan nilai null. Itu tidak bisa mengembalikan null di sini, seperti yang o.IDakan melempar NullReferenceException pada nilai null.
Jon Skeet
11

Dari perpustakaan MSDN:

The First<TSource>(IEnumerable<TSource>)Metode melempar pengecualian jika sumber tidak mengandung unsur-unsur. Untuk mengembalikan nilai default saat urutan sumber kosong, gunakan FirstOrDefaultmetode.

KBoek
sumber
0

Bagi Anda yang menghadapi masalah ini saat membuat pengontrol melalui menu konteks, membuka kembali Visual Studio sebagai administrator memperbaikinya.

Abu
sumber
-4

Mungkin menggunakan Where () before First () dapat membantu Anda, karena masalah saya telah terpecahkan dalam kasus ini.

var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();
Elnaz
sumber
3
Apa yang sebenarnya membantu Anda di sini adalah menggunakan .FirstOrDefault () daripada .First () - using .Where (o => o.ID == id) .FirstOrDefault () dan .FirstOrDefault (o => o.ID == id ) akan sama.
pwdst
@pwdst menggunakan kondisi di klausa Where dan kemudian FirstOrDefault tanpa ekspresi lambda.
Elnaz