Interactive Extensionsを自分で実装する – 8.Finally, For

InteractiveExtensions(Ix)を自分で実装する、第8回はまずFinallyです。

これはDoのonCompletedにActionを設定したものと同じですね、オシマイ!ではさびしすぎるのでまずシグネチャの確認から。

public static IEnumerable<TSource> Finally<TSource>(this IEnumerable<TSource> source, Action finallyAction);

もうわかってきた気がします。。一応使ってみましょう。

static void FinallyTest()
{
    var sequence = Enumerable.Range(1, 5);
    var finallySequence = sequence.Finally(() => Console.WriteLine("finished"));
    foreach (var item in finallySequence)
    {
        Console.WriteLine(item);
    }
}

finally
やや、やっぱり。。Doメソッドでいーぢゃんと思ってしまいますが、イヤチョットマテ。Finallyということは、、

static IEnumerable<int> FinallyTestSequenceWithException()
{
    yield return 1;
    yield return 2;
    throw new Exception("test Exception");
    yield return 3;
}
static void FinallyTest2()
{
    var sequence = FinallyTestSequenceWithException();
    var finallySequence = sequence.Finally(() => Console.WriteLine("finished"));
    try{
        foreach (var item in finallySequence){
            Console.WriteLine(item);
        }
    }
    catch (Exception e){
        Console.WriteLine(e.Message);
    }
}

finally_2

やっぱり!Doの例外発生時はonErrorが呼ばれたあとonCompletedは呼ばれませんが、Finallyは名前の通り呼ばれるようです。

それでは実装です。

Finally…シーケンスの最後に渡したActionを実行する

namespace EmulateInteractiveExtensions
{
    public static class EmulateIxExtensions
    {
        public static IEnumerable<TSource> Finally<TSource>(this IEnumerable<TSource> source, Action finallyAction)
        {
            if (source == null || finallyAction == null){
                throw new ArgumentNullException();
            }

            try{
                foreach (var item in source){
                    yield return item;
                }
            }
            finally{
                finallyAction();
            }
        }
    }
}

必要なのはtry-finallyステートメントなので前回のDoメソッドの時入れられなかったyield returnを入れられてます。

 

続いてFor!シグネチャはこちら。

public static IEnumerable<TResult> For<TSource, TResult>(IEnumerable<TSource> source, Func<TSource,IEnumerable<TResult>> resultSelector);

Caseにちょっとばかし似ていますがsourceがシーケンスなので、resultSelectorにsourceを渡した時のシーケンスが合体して出力されるようですね。SelectManyみたいな動きでしょうか。動作を見てみます。

static void ForTest()
{
    var selector = new[]{
        Enumerable.Range(0, 4),
        Enumerable.Range(4, 4),
        Enumerable.Range(8, 4)
    };
    var sequence = Enumerable.Range(0, 3);
    var forSequence = EmulateIxExtensions.For(sequence, i => selector[i]);
    foreach (var item in forSequence)
    {
        Console.WriteLine(item);
    }
}

for
わかりやすいですね。ではちゃちゃっと実装いきましょう。(Let’s Implement It!)

For…複数のシーケンスを入力シーケンスに基づき平坦化する

namespace EmulateInteractiveExtensions
{
    public static class EmulateIxExtensions
    {
        public static IEnumerable<TResult> For<TSource, TResult>(IEnumerable<TSource> source, Func<TSource,IEnumerable<TResult>> resultSelector)
        {
            if (source == null || resultSelector == null)
            {
                throw new ArgumentNullException();
            }
            foreach (var seed in source)
            {
                var subSequence = resultSelector(seed);
                foreach (var item in subSequence)
                {
                    yield return item;
                }
            }
        }
    }
}
広告

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中