Rx/FirstとTake

Last-modified: 2020-02-04 (火) 22:41:23

違い

FirstTake(1)
Emptyに接続OnError()OnCompleted()

System.LinqのFirst()と同じで、InvalidOperationExceptionが投げられてOnError()が呼ばれる。
一方Take()は流れてくるデータが足りなくてもOnCompleted()が呼ばれる。

テスト

private static void Main(string[] args)
{
    //何も流さず完了
    Observable.Empty<Unit>()
        .FirstAsync()
        .Subscribe(new TestObserver<Unit>("Empty.First"));
    Observable.Empty<Unit>()
        .Take(1)
        .Subscribe(new TestObserver<Unit>("Empty.Take"));

    //1つだけ流して完了
    Observable.Return(Unit.Default)
        .FirstAsync()
        .Subscribe(new TestObserver<Unit>("Return.First"));
    Observable.Return(Unit.Default)
        .Take(1)
        .Subscribe(new TestObserver<Unit>("Return.Take"));

    //10個流して完了
    Observable.Repeat(Unit.Default, 10)
        .FirstAsync()
        .Subscribe(new TestObserver<Unit>("Repeat.First"));
    Observable.Repeat(Unit.Default, 10)
        .Take(1)
        .Subscribe(new TestObserver<Unit>("Repeat.Take"));
}

//テスト用簡易Observer
private class TestObserver<T> : IObserver<T>
{
    public string Tag { get; }

    public TestObserver(string tag)
    {
        Tag = tag;
    }

    public void OnNext(T value)
    {
        Console.WriteLine($"{Tag}#OnNext:{value.ToString()}");
    }

    public void OnError(Exception error)
    {
        Console.WriteLine($"{Tag}#OnError");
    }

    public void OnCompleted()
    {
        Console.WriteLine($"{Tag}#OnCompleted");
    }
}

出力

Empty.First#OnError
Empty.Take#OnCompleted
Return.First#OnNext:()
Return.First#OnCompleted
Return.Take#OnNext:()
Return.Take#OnCompleted
Repeat.First#OnNext:()
Repeat.First#OnCompleted
Repeat.Take#OnNext:()
Repeat.Take#OnCompleted