1
1

ObservableCollections.ObservableDictionaryをReadonlyにしたい

Last updated at Posted at 2024-05-27

これは何

UniRx.ReactiveDictionaryからR3+ObservableCollections.ObservableDictionaryに乗り換えるメモです。

ObservableCollectionsとは

過去にこちらでまとめているので参考にしてください。
R3と連携する方法はこのあたりを参考にして下さい。

ReadOnlyなReactiveなDictionaryが欲しい

UniRx.ReactiveDictionaryの代替としてR3+ObservableCollections.ObservableDictionaryが使えるのですが、ReadOnly化して公開することができません。(UniRx.IReactiveDictionaryに相当するものが無い)

そのため無理やりですがReadOnlyに変換してみます。

ReadOnlyObservableDictionary
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using ObservableCollections;
using R3;

namespace ObservableCollectionsExt
{
    public class ReadOnlyObservableDictionary<TKey, TValue>
        : IReadOnlyObservableDictionary<TKey, TValue> where TKey : notnull
    {
        private ObservableDictionary<TKey, TValue> observableDictionary;

        public ReadOnlyObservableDictionary(ObservableDictionary<TKey, TValue> observableDictionary)
        {
            this.observableDictionary = observableDictionary;
        }

        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() => observableDictionary.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

        public int Count => observableDictionary.Count;

        public bool ContainsKey(TKey key) => observableDictionary.ContainsKey(key);

        public bool TryGetValue(TKey key, out TValue value) => observableDictionary.TryGetValue(key, out value);

        public TValue this[TKey key] => observableDictionary[key];

        public IEnumerable<TKey> Keys => observableDictionary.Select(x => x.Key);
        public IEnumerable<TValue> Values => observableDictionary.Select(x => x.Value);

        public Observable<CollectionAddEvent<KeyValuePair<TKey, TValue>>> ObserveAdd()
            => observableDictionary.ObserveAdd();

        public Observable<int> ObserveCountChanged(bool notifyCurrentCount = false)
            => observableDictionary.ObserveCountChanged();

        public Observable<CollectionRemoveEvent<KeyValuePair<TKey, TValue>>> ObserveRemove()
            => observableDictionary.ObserveRemove();

        public Observable<CollectionReplaceEvent<KeyValuePair<TKey, TValue>>> ObserveReplace()
            => observableDictionary.ObserveReplace();

        public Observable<Unit> ObserveReset()
            => observableDictionary.ObserveReset();
    }

    public interface IReadOnlyObservableDictionary<TKey, TValue> : IReadOnlyDictionary<TKey, TValue>
    {
        Observable<CollectionAddEvent<KeyValuePair<TKey, TValue>>> ObserveAdd();
        Observable<int> ObserveCountChanged(bool notifyCurrentCount = false);
        Observable<CollectionRemoveEvent<KeyValuePair<TKey, TValue>>> ObserveRemove();
        Observable<CollectionReplaceEvent<KeyValuePair<TKey, TValue>>> ObserveReplace();
        Observable<Unit> ObserveReset();
    }

    public static class ObservableCollectionsExt
    {
        public static IReadOnlyObservableDictionary<TKey, TValue> ToReadOnlyObservableDictionary<TKey, TValue>(
            this ObservableDictionary<TKey, TValue> observableDictionary)
            where TKey : notnull
            => new ReadOnlyObservableDictionary<TKey, TValue>(observableDictionary);
    }
}
使い方
using ObservableCollections;
using ObservableCollectionsExt;
using R3;

// オリジナル
var original = new ObservableDictionary<int, string>();

// ReadOnly化
var readOnlyDic = original.ToReadOnlyObservableDictionary();

// オリジナルと同じ様に参照可能
readOnlyDic.ObserveAdd().Subscribe(x=> Console.WriteLine(x));
readOnlyDic.ObserveRemove().Subscribe(x=> Console.WriteLine(x));
readOnlyDic.ObserveReplace().Subscribe(x=> Console.WriteLine(x));
readOnlyDic.ObserveCountChanged().Subscribe(Console.WriteLine);

original[0] = "1";
original[0] = "2";
original[1] = "3";
original[4] = "4";
original.Remove(0);
original.Clear();
original[1] = "aa";

Console.WriteLine(readOnlyDic[1]);

感想

  • ReadonlyなObservableDictionaryは欲しいから用意してみた
  • ただし変換時にクラスをインスタンス化するためコストあり
    • 使うならキャッシュして使い回すようにしましょう
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