1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

ReactiveCommand.WithSubscribe() 使用時の RC本体の破棄について

Posted at

はじめに

@okazuki さん がメンテナーを務めておられる ReactiveProperty に関する記事になります。
趣味のWPFアプリ開発で長い間 愛用させていただいているのですが、勘違い(勝手な思い込み)をしているところが見つかり、かずき さんに質問した内容をまとめた記事になります。

知ってる人にはとっては「今更何言っての?」って内容かもしれません 😭

本題

ReactiveCommand を作成する場合、 WithSubscrbe() を使って Action の購読までメソッドチェーンで一気に書くことがあります。
以下のコードでは ICommand.CanExecute() を 1秒ごとに切り替えます。

TimerCommand = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
    .Select(x => (x & 1) == 0)
    .ToReactiveCommand()
    .WithSubscribe(() => Message = $"Clicked!", _disposables.Add);

WithSubscribe()Disposer を指定しており、_disposables.Dispose() を実行すれば 後腐れなく全てが破棄 される。 と思い込んでおりましたが、その認識は間違いでした。

実際に Disposer に登録されるのは 購読した Action のみで、 ReactiveCommand 自体は登録されません。
そのため上のコードでは、_disposables.Dispose() 後も Timer が動作し続けて、ReactiveCommand.CanExecute() は変化し続けます。(Action は破棄済みなので Command を実行しても何も起きません)

対策

ReactiveCommand.WithSubscribe() の使用時は ReactiveCommand 自体も破棄の対象に登録しましょう。

TimerCommand = Observable.Timer(TimeSpan.FromSeconds(0), TimeSpan.FromSeconds(1))
    .Select(x => (x & 1) == 0)
    .ToReactiveCommand()
    .WithSubscribe(() => Message = $"Clicked!", _disposables.Add)
    .AddTo(_disposables);    // ◆これが必要!!

思い込みって怖いですね。

サンプルコード

hsytkm/RpTimerDemo: Dispose ReactiveCommand when using WithSubscribe method.

環境

VisualStudio 2022 17.2.0 Preview 1.0

.NET 6.0 + C# 10.0 + WPF

ReactiveProperty 8.0.3

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?