2

私はコレクションを持っています

List<KeyValuePair<string, Details>> x

どこ

public class Details
{ 
    private int x;
    private int y;

    public Details()
    {
        x = 0;
        y = 0;
    }
    ...
}

コレクションでLINQを使用して、Detailsインスタンスを返します

x.Where(x => x.Key == aString).SingleOrNew().Value

は次.SingleOrNewのように定義されています

public static T SingleOrNew<T>(this IEnumerable<T> query) where T : new()
{            
    try
    {
       return query.Single();
    }
    catch (InvalidOperationException)
    {
       return new T();
    }
}

そのため、 a が節を満たすKeyValuePair<string, Details>リストに見つからない場合、 aが返されます。xWherenew KeyValuePair<string, Details>

しかし問題はnull の Details 値new KeyValuePair<string, Details>が含まれていることです。

句から一致が見つからない場合、 like.Whereを返す LINQ (拡張) メソッドを使用できるかどうか疑問に思っていましたが、デフォルトのパラメーターなしのコンストラクターを使用して/の部分が初期化されていますか? そのため、null ではありません。new KeyValuePair<string, Details>SingleOrNew.ValueDetailsKeyValuePairDetails

4

2 に答える 2

5

代わりに、次の拡張メソッドを使用してください。

    public static T SingleOrNew<T>(this IEnumerable<T> query, Func<T> createNew) 
    {
        try
        {
            return query.Single();
        }
        catch (InvalidOperationException)
        {
            return createNew();
        }
    }

これも必要な場合があるため、Where() 句は必要ありません。

    public static T SingleOrNew<T>(this IEnumerable<T> query, Func<T,bool> predicate, Func<T> createNew) 
    {
        try
        {
            return query.Single(predicate);
        }
        catch (InvalidOperationException)
        {
            return createNew();
        }
    }

これで、T の既定値に制限されたり、パブリック パラメーターなしのコンストラクターの制約を受ける代わりに、T の新しいインスタンスがどうあるべきかを指定できるようになりました。

于 2011-03-11T17:59:22.070 に答える
1

実際、私はこのようにします

public static T SingleOrNew<T>(this IEnumerable<T> query, Func<T> createNew)
{
    using (var enumerator = query.GetEnumerator())
    {
        if (enumerator.MoveNext() && !enumerator.MoveNext())
        {
            return enumerator.Current;
        }
        else
        {
            return createNew();
        }
    }
}

例外をキャッチしてシナリオをテストするのは好きではありません。

説明:

まず、Enumerable の Enumerator を取得しています。MoveNextEnumerator は、メソッドとCurrentプロパティを持つオブジェクトです。このMoveNextメソッドはCurrent、列挙型の次の値 (存在する場合) に設定し、移動先の値が他にある場合は true を返し、移動先の値がない場合は false を返します。さらに、列挙子は using ステートメント内にラップされ、処理が完了したら確実に破棄されます。

したがって、列挙子を取得したら、 を呼び出しますMoveNext。それが false を返す場合、列挙型は空であり、else ステートメントに直接進み (短絡評価のために 2 番目の MoveNext メソッドをバイパスします)、 の結果を返しcreateNewます。最初の呼び出しで true が返された場合は、MoveNext再度呼び出して、2 番目の値がないことを確認する必要があります (Single 値が必要なため)。2 番目の呼び出しが true を返す場合、else ステートメントに移動し、 の結果を返しcreateNewます。Enumerable に値が 1 つしかない場合、 への最初の呼び出しMoveNextは true を返し、2 番目の呼び出しは false を返しCurrent、最初の への呼び出しによって設定された値を返しますMoveNext

FirstOrNewへの 2 番目の呼び出しを削除することで、これを に変更できますMoveNext

于 2011-03-11T21:24:59.017 に答える