Sequenz enthält keine passenden Element

112

Ich habe eine asp.net-Anwendung, in der ich linq zur Datenmanipulation verwende. Während des Laufens erhalte ich die Ausnahme "Sequenz enthält kein passendes Element".

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
quelle

Antworten:

218

Nun, ich würde erwarten, dass es diese Zeile ist, die die Ausnahme auslöst:

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

First()löst eine Ausnahme aus, wenn keine passenden Elemente gefunden werden können. Da Sie unmittelbar danach auf null testen, klingt dies wie gewünscht. Dabei FirstOrDefault()wird der Standardwert für den Elementtyp (der für Referenztypen null ist) zurückgegeben, wenn keine übereinstimmenden Elemente gefunden werden:

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

Andere Optionen, die in einigen Situationen in Betracht gezogen werden müssen, sind Single()(wenn Sie glauben, dass es genau ein übereinstimmendes Element gibt) und SingleOrDefault()(wenn Sie glauben, dass es genau ein oder null übereinstimmende Elemente gibt). Ich vermute, dass FirstOrDefaultdies in diesem speziellen Fall die beste Option ist, aber es lohnt sich trotzdem, über die anderen Bescheid zu wissen.

Auf der anderen Seite sieht es so aus, als ob Sie mit einem Join hier überhaupt besser dran wären. Wenn es Ihnen egal wäre, dass alle Übereinstimmungen (und nicht nur die ersten) ausgeführt werden, können Sie Folgendes verwenden:

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
}

Das ist einfacher und effizienter IMO.

Auch wenn Sie sich entscheiden, die Schleife zu halten, habe ich einige Vorschläge:

  • Werde das Äußere los if. Sie brauchen es nicht, denn wenn Count Null ist, wird der for-Schleifenkörper niemals ausgeführt
  • Verwenden Sie exklusive Obergrenzen für for-Schleifen - sie sind in C # idiomatischer:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Beseitigen Sie häufige Unterausdrücke:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Verwenden Sie nach Möglichkeit foreachanstelle von for:

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

Verwenden Sie FirstOrDefault . First gibt niemals null zurück. Wenn kein passendes Element gefunden wird, wird die angezeigte Ausnahme ausgelöst.

_dsACL.Documents.FirstOrDefault(o => o.ID == id);
Jakub Konecki
quelle
19
Nur zur Verdeutlichung - First könnte im Allgemeinen null zurückgeben, wenn Ihr Prädikat mit null Werten übereinstimmt. Es kann hier einfach nicht null zurückgeben, da o.IDdies eine NullReferenceException auf einen Nullwert auslösen würde.
Jon Skeet
11

Aus der MSDN-Bibliothek:

Die First<TSource>(IEnumerable<TSource>)Methode löst eine Ausnahme aus, wenn die Quelle keine Elemente enthält. Verwenden Sie die FirstOrDefaultMethode , um stattdessen einen Standardwert zurückzugeben, wenn die Quellsequenz leer ist .

KBoek
quelle
0

Für diejenigen unter Ihnen, die dieses Problem beim Erstellen eines Controllers über das Kontextmenü hatten, wurde es durch erneutes Öffnen von Visual Studio als Administrator behoben.

Asche
quelle
-4

Vielleicht kann es Ihnen helfen, Where () vor First () zu verwenden, da mein Problem in diesem Fall gelöst wurde.

var documentRow = _dsACL.Documents.Where(o => o.ID == id).FirstOrDefault();
Elnaz
quelle
3
Was Ihnen hier tatsächlich geholfen hat, ist die Verwendung von .FirstOrDefault () anstelle von .First () - die Verwendung von .Where (o => o.ID == id) .FirstOrDefault () und .FirstOrDefault (o => o.ID == id) ) wird identisch sein.
pwdst
@pwdst unter Verwendung der Bedingung in der Where-Klausel und dann FirstOrDefault ohne Lambda-Ausdruck.
Elnaz