かずきのBlog@hatena

すきな言語は C# + XAML の組み合わせ。Azure Functions も好き。最近は Go 言語勉強中。日本マイクロソフトで働いていますが、ここに書いていることは個人的なメモなので会社の公式見解ではありません。

ReactivePropertyの後始末

久しぶりのReactivePropertyネタです。

ReactiveProperty, ReadOnlyReactiveProperty, ReactiveCommand等は、地味にIDisposableを実装しています。 IDisposableを実装しているということは、Disposeをしないといけないということになります。

Disposeしなくてもいいケース

ただ、必ずしもDisposeしないとまずいかというとそうでもありません。例えば以下のようなケース。

public ReactiveProperty<string> Input { get; } = new ReactiveProperty<string>();

自己完結してるような時は特にDispose必要ありません。

Disposeしないといけないケース

他のIObservableをソースとしてReactivePropertyなんかを作ったときは、内部動作としてSubscribeをしているので、Disposeを呼ぶ必要があります。例えば以下のようなケースです。

public ReactiveProperty<string> Name { get; }

public Ctor(Person model)
{
    // ObservePropertyでPropertyChangedを購読して、それをSubscribeしている!
    this.Name = model.ObserveProperty(x => x.Name).ToReactiveProperty();
}

こういう時は、ReactivePropertyを持っているクラスが不要になったタイミングでDisposeを呼んでやらないと、予期せぬ動作をすることがあるかもしれません。

Disposeを楽にする方法

1つ1つDisposeを呼んで回るのは大変なのでReactive ExtensionsのCompositeDisposableに、Addしていって一括Disposeができるようにするのが楽でいいです。

private CompositeDisposable Disposable { get; } = new CompositeDisposable();

// RPの定義
public ReactiveProperty<string> PropA { get; }
public ReactiveProperty<string> PropB { get; }

public Ctor()
{
    this.PropA = hogeObservable.ToReactiveProperty();
    this.PropB = fugaObservable.ToReactiveProperty();
    // Disposeを集めておく
    this.Disposable.Add(this.PropA);
    this.Disposable.Add(this.PropA);
}

public SomeCleanupMethod()
{
    // 一括Dispose!
    this.Disposable.Dispose();
}

ただ、ReactivePropertyを生成するのと、CompositeDisposableに集めるのと別ステートメントになってめんどくさいです。ということで、IDisposableの拡張メソッドとしてAddToメソッドを提供しています。これを使うと以下のように書けるようになります。

private CompositeDisposable Disposable { get; } = new CompositeDisposable();

// RPの定義
public ReactiveProperty<string> PropA { get; }
public ReactiveProperty<string> PropB { get; }

public Ctor()
{
    // RPを作りつつCompositeDisposableに登録できる
    this.PropA = hogeObservable.ToReactiveProperty().AddTo(this.Disposable);
    this.PropB = fugaObservable.ToReactiveProperty().AddTo(this.Disposable);
}

public SomeCleanupMethod()
{
    // 一括Dispose!
    this.Disposable.Dispose();
}

まとめ

ということで、後始末はきちんとしましょう!そして、楽に後始末するためにはCompositeDisposableとAddToメソッドを使いましょうということでした。