【UniRx】ReactivePropertyのスニペット

UniRx の利用例に ReactiveProperty を public で公開する実装が例示されていたりするのですがそれはちょっと違うんじゃないかなと思ったので記事にしました。

簡単な実装例

public readonly ReactiveProperty<int> Value = new ReactiveProperty<int>();
// IntReactiveProperty でも同じ

上記ですが(まぁ大したことではないのですが)利用者側に Rx を使っていることが公開されているのと、付随して値へのアクセスが Xxxx.Value となるため相手に実装が微妙に漏れているのためやや微妙かもしれません。

完全に実装を隠蔽する場合以下のように書くことになります。

// [非公開] 中身で使用するRxの実態
private readonly ReactiveProperty<string> _sampleStr = new();

// 値の変更はプロパティ経由で行う = Rx を使用している子を公開しない
public string SampleStr { get => _sampleStr.Value; set => _sampleStr.Value = value; }

// 通知を受け取りたい(Subscribeさせたい)イベント通知はSystem.IObservable経由で行う
public IObservable<string> SampleStrChanged => _sampleStr;

ただし毎回これ書くのはかなり面倒なので VisualStudio 向けにスニペットを作成しました。

「rx」と入力して補完候補を選んで「Tab」を2回入力します。

スニペットの中身は以下の通りです。

Gist - rx.snippet

// rx.snippet

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>rx</Title>
      <Shortcut>rx</Shortcut>
      <Description>ReactiveProp</Description>
      <Author></Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>valueType</ID>
          <Default>int</Default>
          <ToolTip>公開する変数の型で置き換えます。</ToolTip>
        </Literal>
        <Literal>
          <ID>propName</ID>
          <Default>Sample</Default>
          <ToolTip>公開するプロパティの名前で置き換えます。</ToolTip>
        </Literal>
        <Literal>
          <ID>fieldName</ID>
          <Default>sample</Default>
          <ToolTip>内部で使用する変数の名前で置き換えます。</ToolTip>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[public $valueType$ $propName$ { get => _$fieldName$.Value; set => _$fieldName$.Value = value; }
public System.IObservable<$valueType$> $propName$Changed => _$fieldName$;
private readonly UniRx.ReactiveProperty<$valueType$> _$fieldName$ = new();$end$]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

このスニペットの展開結果は以下の通りです。

public int Sample { get => _sample.Value; set => _sample.Value = value; }
public System.IObservable<int> SampleChanged => _sample;
private readonly UniRx.ReactiveProperty<int> _sample = new();

また以下の Suject のみ作成してイベント通知するスニペットは以下の通りです。

スニペットの中身は以下の通りです。rxs のキーショットカットで呼び出すことができます。

Gist - rxs.snippet

<?xml version="1.0" encoding="utf-8" ?>
<CodeSnippets  xmlns="http://schemas.microsoft.com/VisualStudio/2005/CodeSnippet">
  <CodeSnippet Format="1.0.0">
    <Header>
      <Title>rx</Title>
      <Shortcut>rxs</Shortcut>
      <Description>ReactiveProp</Description>
      <Author></Author>
    </Header>
    <Snippet>
      <Declarations>
        <Literal>
          <ID>valueType</ID>
          <Default>int</Default>
          <ToolTip>公開する変数の型で置き換えます。</ToolTip>
        </Literal>
        <Literal>
          <ID>propName</ID>
          <Default>Sample</Default>
          <ToolTip>公開するプロパティの名前で置き換えます。</ToolTip>
        </Literal>
        <Literal>
          <ID>fieldName</ID>
          <Default>sample</Default>
          <ToolTip>内部で使用する変数の名前で置き換えます。</ToolTip>
        </Literal>
      </Declarations>
      <Code Language="csharp"><![CDATA[public System.IObservable<$valueType$> $propName$ => _$fieldName$;
private readonly UniRx.Subject<$valueType$> _$fieldName$ = new();$end$]]></Code>
    </Snippet>
  </CodeSnippet>
</CodeSnippets>

このスニペットの展開結果は以下の通りです。

public System.IObservable<int> Sample => _sample;
private readonly UniRx.Subject<int> _sample = new();

上記をコピペ → snippet ファイルとして保存する or gist から取得して VisualStudio の ツール > コード スニペット マネージャー からインポートすると使えるようになります。

あと可能であればこれで生成した Reactive な変数は使い終わったら宣言側でも Dispose した方が安全です。

public System.IObservable<int> Sample => _sample;
private readonly UniRx.Subject<int> _sample = new();

private void Awake()
{
    _sample.AddTo(this); // Destroyしたときに一緒に破棄する
}

// もしくは

private void OnDestory()
{
    using(_sample) { } // Destory時に明示的に破棄する
}

宣言側でイベントのリークなどの深刻な問題がに直ちに直結する可能性低いですがお作法 IDisposable なフィールドは Dispose しておいた方が無難かと思います。