シーケンスに一致する要素が含まれていません


112

データ操作にlinqを使用しているasp.netアプリケーションがあります。実行中に、「シーケンスに一致する要素が含まれていません」という例外が発生します。

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()、一致する項目が見つからない場合、要素タイプのデフォルト値(参照タイプの場合はnull)を返すように聞こえます。

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

状況によっては、Single()(一致する要素が1つSingleOrDefault()だけであると確信している場合)と(一致する要素が1つまたは0であると確信している場合)に検討すべき他のオプションがあります。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ループ本体は実行されないため、これは必要ありません。
  • 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)

39

FirstOrDefaultを使用します。最初にnullが返されることはありません。一致する要素が見つからない場合は、表示されている例外がスローされます。

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

19
少し明確にするために- 述語がnull値に一致した場合、First 一般にnullを返す可能性があります。ここでo.IDは、null値に対してNullReferenceExceptionをスローするように、nullを返すことはできません。
Jon Skeet、

11

MSDNライブラリから:

First<TSource>(IEnumerable<TSource>)ソース要素が含まれていない場合メソッドは例外をスローします。ソースシーケンスが空のときに代わりにデフォルト値を返すには、FirstOrDefaultメソッドを使用します。


0

コンテキストメニューからコントローラーを作成しているときにこの問題に直面した人のために、管理者がVisual Studioを再度開いて修正しました。


-4

この場合は私の問題が解決されているので、First()の前にWhere()を使用すると役立つ場合があります。

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

3
ここで実際に役に立ったのは、.First()の代わりに.FirstOrDefault()を使用することです-.Where(o => o.ID == id).FirstOrDefault()と.FirstOrDefault(o => o.ID == id )は同じになります。
pwdst 2017年

Where句の条件を使用し、ラムダ式なしでFirstOrDefaultを使用する@pwdst。
Elnaz 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.