読者です 読者をやめる 読者になる 読者になる

かずきのBlog@hatena

日本マイクロソフトに勤めています。XAML + C#の組み合わせをメインに、たまにASP.NETやJavaなどの.NET系以外のことも書いています。掲載内容は個人の見解であり、所属する企業を代表するものではありません。

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メソッドを使いましょうということでした。