1

IgnoreNullItems以下のサンプル コードで拡張メソッドを呼び出すと、遅延実行は期待どおりに機能しますが、使用するIgnoreNullItemsHavingDifferentBehaviourとすぐに例外が発生します。なんで?

List<string> testList = null;
testList.IgnoreNullItems(); //nothing happens as expected

testList.IgnoreNullItems().FirstOrDefault();
//raises ArgumentNullException as expected

testList.IgnoreNullItemsHavingDifferentBehaviour(); 
//raises ArgumentNullException immediately. not expected behaviour -> 
//  why is deferred execution not working here?

アイデアを共有していただきありがとうございます。

ラファエル・ザゲット

public static class EnumerableOfTExtension
{
    public static IEnumerable<T> IgnoreNullItems<T>(this IEnumerable<T> source)
        where T: class
    {
        if (source == null) throw new ArgumentNullException("source");

        foreach (var item in source)
        {
            if (item != null)
            {
                yield return item;
            }
        }
        yield break;
    }

    public static IEnumerable<T> IgnoreNullItemsHavingDifferentBehaviour<T>(
        this IEnumerable<T> source) 
        where T : class
    {
        if (source == null) throw new ArgumentNullException("source");

        return IgnoreNulls(source);
    }

    private static IEnumerable<T> IgnoreNulls<T>(IEnumerable<T> source)
        where T : class
    {
        foreach (var item in source)
        {
            if (item != null)
            {
                yield return item;
            }
        }
        yield break;
    }
}

同じ動作のバージョンを次に示します。

これは、同じ動作を示すバージョンです。この場合、resharper に foreach ステートメントを「改善」させないでください ;) --> resharper は、return ステートメントを使用して foreach を「IgnoreNullItemsHavingDifferentBehaviour」バージョンに変更します。

public static IEnumerable<T> IgnoreNullItemsHavingSameBehaviour<T>(this IEnumerable<T> source) where T : class
            {
                if (source == null) throw new ArgumentNullException("source");

                foreach (var item in IgnoreNulls(source))
                {
                    yield return item;
                }
                yield break;
            }
4

3 に答える 3

5

IgnoreNullItemsHavingDifferentBehaviourには「yield」自体が含まれていないため、例外がすぐに発生します。

むしろ、反復子ブロックに変換されるのはIgnoreNullsであり、したがって遅延実行を使用します。

これは、Jon Skeet が EduLinq シリーズでソース シーケンスの即時 null チェックを強制するために使用したアプローチです。より詳細な説明については、この投稿を参照してください(具体的には、「実装してみましょう」セクション)。

于 2011-04-28T11:19:00.487 に答える
4

遅延実行は、どのように機能するかに由来しますyield return。メソッド内にステートマシンを作成し、最初のアイテムを列挙しようとするまでコードを開始または実行しません。

ただし、ないyield return場合は通常の方法と同じように動作します。

Jon Skeet のEdulinqで完全に説明および表示されています。

于 2011-04-28T11:20:32.980 に答える