La sequenza non contiene elementi corrispondenti


112

Ho un'applicazione asp.net in cui utilizzo linq per la manipolazione dei dati. Durante l'esecuzione, ottengo l'eccezione "La sequenza non contiene elementi corrispondenti".

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

Risposte:


220

Bene, mi aspetto che sia questa linea a lanciare l'eccezione:

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

First()genererà un'eccezione se non riesce a trovare alcun elemento corrispondente. Dato che stai testando null subito dopo, suona come vuoi FirstOrDefault(), che restituisce il valore predefinito per il tipo di elemento (che è null per i tipi di riferimento) se non vengono trovati elementi corrispondenti:

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

Altre opzioni da considerare in alcune situazioni sono Single()(quando credi che ci sia esattamente un elemento corrispondente) e SingleOrDefault()(quando credi che ci sia esattamente uno o zero elementi corrispondenti). Sospetto che FirstOrDefaultsia l'opzione migliore in questo caso particolare, ma vale comunque la pena conoscere gli altri.

D'altra parte, sembra che potresti davvero stare meglio con un join qui in primo luogo. Se non ti importava che avrebbe fatto tutte le corrispondenze (piuttosto che solo la prima) potresti usare:

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
}

Questo è IMO più semplice ed efficiente.

Anche se non decide di mantenere il loop, ho un paio di suggerimenti:

  • Sbarazzati dell'esterno if. Non ne hai bisogno, come se Count fosse zero, il corpo del ciclo for non verrà mai eseguito
  • Usa limiti superiori esclusivi nei cicli for: sono più idiomatici in C #:

    for (i = 0; i < _lstAcl.Documents.Count; i++)
  • Elimina le sottoespressioni comuni:

    var target = _lstAcl.Documents[i];
    // Now use target for the rest of the loop body
  • Dove possibile utilizzare foreachinvece di foriniziare con:

    foreach (var target in _lstAcl.Documents)

39

Usa FirstOrDefault . Il primo non restituirà mai null: se non riesce a trovare un elemento corrispondente, genera l'eccezione che stai vedendo.

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

19
Giusto per chiarire un po ': First potrebbe restituire null in generale, se il tuo predicato corrispondesse a valori null. Semplicemente non può restituire null qui, poiché o.IDgenererebbe un'eccezione NullReferenceException su un valore null.
Jon Skeet

11

Dalla libreria MSDN:

Il First<TSource>(IEnumerable<TSource>)metodo genera un'eccezione se source non contiene elementi. Per restituire invece un valore predefinito quando la sequenza di origine è vuota, utilizzare il FirstOrDefaultmetodo.


0

Per quelli di voi che hanno affrontato questo problema durante la creazione di un controller tramite il menu di scelta rapida, riaprendo Visual Studio come amministratore è stato risolto.


-4

Forse usare Where () prima di First () può aiutarti, poiché il mio problema è stato risolto in questo caso.

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

3
Ciò che ti ha effettivamente aiutato qui è usare .FirstOrDefault () invece di .First () - usando .Where (o => o.ID == id) .FirstOrDefault () e .FirstOrDefault (o => o.ID == id ) sarà identico.
pwdst

@pwdst utilizzando la condizione nella clausola Where e quindi FirstOrDefault senza alcuna espressione lambda.
Elnaz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.