18

Enumerable.Single逆コンパイラで検査しているときに、メソッドで(大まかに)このコードを見つけました。

foreach (TSource current in source)
{
    if (predicate(current))
    {
        result = current;
        num += 1L;
    }
}

if (num > 1L)
{
     throw Error.MoreThanOneMatch();
}

ご覧のとおり、スローする前にすべてのアイテムをループします。なぜ壊れないのnum > 1ですか?

4

2 に答える 2

4

パフォーマンスの点でより良いことに同意します(編集:述語に一致するアイテムが複数あると予想される場合、これは行うべきではありません):

foreach (TSource current in source)
{
    if (predicate(current))
    {
        result = current;
        num += 1L;

        if (num > 1L)
            throw Error.MoreThanOneMatch();
    }
}

if (num == 0L)
   throw Error.NoMatch();

return local;

彼らは、分析結果をより明確にし、列挙ソースから分離することを決定したようです。しかし、なぜ単純なスイッチが使用されなかったのだろうか:

switch((int)num)
{
   case 0: throw Error.NoMatch();
   case 1: return local;
   default:
       throw Error.MoreThanOneMatch();    
}

パフォーマンスの問題に関しては、単一の結果を本当に期待してSingleいるときに呼び出す必要があると想定されていると思います。ゼロ以上の結果は例外的なパスであり、(例外として) 頻繁に発生するべきではありません。したがって、ソースに述語に一致する多くの項目が含まれていると、プログラムの論理エラーになります。

于 2013-07-19T09:59:45.573 に答える
0

とは、正確に 1 つ、なしではなく、1 つを超えないことSingleを意味します。すべての項目を 列挙して、1 つだけであることを確認します。 存在しない場合、または複数存在する場合は、例外がスローされます。代わりに、それ以上ある場合はスローしますが、ない場合は/を返します。


SingleOrDefaultdefault(T)null

あなたが探しているのはFirstOrDefault、述語に一致する最初のものが見つかった場合、列挙を壊すことです。First代わりに、何もない場合はスローし、最初のものが見つかった場合は foreach を中断します (から直接戻ります)。

FirstOrDefault のソース

foreach (TSource current in source)
{
    if (predicate(current))
    {
        return current;
    }
}
return default(TSource);

一方、First のソースは return default ではなく

throw Error.NoMatch();
于 2013-07-19T10:15:59.690 に答える