ReactiveDictionary.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Runtime.Serialization;
  5. namespace UniRx
  6. {
  7. public struct DictionaryAddEvent<TKey, TValue> : IEquatable<DictionaryAddEvent<TKey, TValue>>
  8. {
  9. public TKey Key { get; private set; }
  10. public TValue Value { get; private set; }
  11. public DictionaryAddEvent(TKey key, TValue value)
  12. : this()
  13. {
  14. Key = key;
  15. Value = value;
  16. }
  17. public override string ToString()
  18. {
  19. return string.Format("Key:{0} Value:{1}", Key, Value);
  20. }
  21. public override int GetHashCode()
  22. {
  23. return EqualityComparer<TKey>.Default.GetHashCode(Key) ^ EqualityComparer<TValue>.Default.GetHashCode(Value) << 2;
  24. }
  25. public bool Equals(DictionaryAddEvent<TKey, TValue> other)
  26. {
  27. return EqualityComparer<TKey>.Default.Equals(Key, other.Key) && EqualityComparer<TValue>.Default.Equals(Value, other.Value);
  28. }
  29. }
  30. public struct DictionaryRemoveEvent<TKey, TValue> : IEquatable<DictionaryRemoveEvent<TKey, TValue>>
  31. {
  32. public TKey Key { get; private set; }
  33. public TValue Value { get; private set; }
  34. public DictionaryRemoveEvent(TKey key, TValue value)
  35. : this()
  36. {
  37. Key = key;
  38. Value = value;
  39. }
  40. public override string ToString()
  41. {
  42. return string.Format("Key:{0} Value:{1}", Key, Value);
  43. }
  44. public override int GetHashCode()
  45. {
  46. return EqualityComparer<TKey>.Default.GetHashCode(Key) ^ EqualityComparer<TValue>.Default.GetHashCode(Value) << 2;
  47. }
  48. public bool Equals(DictionaryRemoveEvent<TKey, TValue> other)
  49. {
  50. return EqualityComparer<TKey>.Default.Equals(Key, other.Key) && EqualityComparer<TValue>.Default.Equals(Value, other.Value);
  51. }
  52. }
  53. public struct DictionaryReplaceEvent<TKey, TValue> : IEquatable<DictionaryReplaceEvent<TKey, TValue>>
  54. {
  55. public TKey Key { get; private set; }
  56. public TValue OldValue { get; private set; }
  57. public TValue NewValue { get; private set; }
  58. public DictionaryReplaceEvent(TKey key, TValue oldValue, TValue newValue)
  59. : this()
  60. {
  61. Key = key;
  62. OldValue = oldValue;
  63. NewValue = newValue;
  64. }
  65. public override string ToString()
  66. {
  67. return string.Format("Key:{0} OldValue:{1} NewValue:{2}", Key, OldValue, NewValue);
  68. }
  69. public override int GetHashCode()
  70. {
  71. return EqualityComparer<TKey>.Default.GetHashCode(Key) ^ EqualityComparer<TValue>.Default.GetHashCode(OldValue) << 2 ^ EqualityComparer<TValue>.Default.GetHashCode(NewValue) >> 2;
  72. }
  73. public bool Equals(DictionaryReplaceEvent<TKey, TValue> other)
  74. {
  75. return EqualityComparer<TKey>.Default.Equals(Key, other.Key) && EqualityComparer<TValue>.Default.Equals(OldValue, other.OldValue) && EqualityComparer<TValue>.Default.Equals(NewValue, other.NewValue);
  76. }
  77. }
  78. // IReadOnlyDictionary is from .NET 4.5
  79. public interface IReadOnlyReactiveDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, TValue>>
  80. {
  81. int Count { get; }
  82. TValue this[TKey index] { get; }
  83. bool ContainsKey(TKey key);
  84. bool TryGetValue(TKey key, out TValue value);
  85. IObservable<DictionaryAddEvent<TKey, TValue>> ObserveAdd();
  86. IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false);
  87. IObservable<DictionaryRemoveEvent<TKey, TValue>> ObserveRemove();
  88. IObservable<DictionaryReplaceEvent<TKey, TValue>> ObserveReplace();
  89. IObservable<Unit> ObserveReset();
  90. }
  91. public interface IReactiveDictionary<TKey, TValue> : IReadOnlyReactiveDictionary<TKey, TValue>, IDictionary<TKey, TValue>
  92. {
  93. }
  94. [Serializable]
  95. public class ReactiveDictionary<TKey, TValue> : IReactiveDictionary<TKey, TValue>, IDictionary<TKey, TValue>, IEnumerable, ICollection<KeyValuePair<TKey, TValue>>, IEnumerable<KeyValuePair<TKey, TValue>>, IDictionary, IDisposable
  96. #if !UNITY_METRO
  97. , ISerializable, IDeserializationCallback
  98. #endif
  99. {
  100. [NonSerialized]
  101. bool isDisposed = false;
  102. #if !UniRxLibrary
  103. [UnityEngine.SerializeField]
  104. #endif
  105. readonly Dictionary<TKey, TValue> inner;
  106. public ReactiveDictionary()
  107. {
  108. inner = new Dictionary<TKey, TValue>();
  109. }
  110. public ReactiveDictionary(IEqualityComparer<TKey> comparer)
  111. {
  112. inner = new Dictionary<TKey, TValue>(comparer);
  113. }
  114. public ReactiveDictionary(Dictionary<TKey, TValue> innerDictionary)
  115. {
  116. inner = innerDictionary;
  117. }
  118. public TValue this[TKey key]
  119. {
  120. get
  121. {
  122. return inner[key];
  123. }
  124. set
  125. {
  126. TValue oldValue;
  127. if (TryGetValue(key, out oldValue))
  128. {
  129. inner[key] = value;
  130. if (dictionaryReplace != null) dictionaryReplace.OnNext(new DictionaryReplaceEvent<TKey, TValue>(key, oldValue, value));
  131. }
  132. else
  133. {
  134. inner[key] = value;
  135. if (dictionaryAdd != null) dictionaryAdd.OnNext(new DictionaryAddEvent<TKey, TValue>(key, value));
  136. if (countChanged != null) countChanged.OnNext(Count);
  137. }
  138. }
  139. }
  140. public int Count
  141. {
  142. get
  143. {
  144. return inner.Count;
  145. }
  146. }
  147. public Dictionary<TKey, TValue>.KeyCollection Keys
  148. {
  149. get
  150. {
  151. return inner.Keys;
  152. }
  153. }
  154. public Dictionary<TKey, TValue>.ValueCollection Values
  155. {
  156. get
  157. {
  158. return inner.Values;
  159. }
  160. }
  161. public void Add(TKey key, TValue value)
  162. {
  163. inner.Add(key, value);
  164. if (dictionaryAdd != null) dictionaryAdd.OnNext(new DictionaryAddEvent<TKey, TValue>(key, value));
  165. if (countChanged != null) countChanged.OnNext(Count);
  166. }
  167. public void Clear()
  168. {
  169. var beforeCount = Count;
  170. inner.Clear();
  171. if (collectionReset != null) collectionReset.OnNext(Unit.Default);
  172. if (beforeCount > 0)
  173. {
  174. if (countChanged != null) countChanged.OnNext(Count);
  175. }
  176. }
  177. public bool Remove(TKey key)
  178. {
  179. TValue oldValue;
  180. if (inner.TryGetValue(key, out oldValue))
  181. {
  182. var isSuccessRemove = inner.Remove(key);
  183. if (isSuccessRemove)
  184. {
  185. if (dictionaryRemove != null) dictionaryRemove.OnNext(new DictionaryRemoveEvent<TKey, TValue>(key, oldValue));
  186. if (countChanged != null) countChanged.OnNext(Count);
  187. }
  188. return isSuccessRemove;
  189. }
  190. else
  191. {
  192. return false;
  193. }
  194. }
  195. public bool ContainsKey(TKey key)
  196. {
  197. return inner.ContainsKey(key);
  198. }
  199. public bool TryGetValue(TKey key, out TValue value)
  200. {
  201. return inner.TryGetValue(key, out value);
  202. }
  203. public Dictionary<TKey, TValue>.Enumerator GetEnumerator()
  204. {
  205. return inner.GetEnumerator();
  206. }
  207. void DisposeSubject<TSubject>(ref Subject<TSubject> subject)
  208. {
  209. if (subject != null)
  210. {
  211. try
  212. {
  213. subject.OnCompleted();
  214. }
  215. finally
  216. {
  217. subject.Dispose();
  218. subject = null;
  219. }
  220. }
  221. }
  222. #region IDisposable Support
  223. private bool disposedValue = false;
  224. protected virtual void Dispose(bool disposing)
  225. {
  226. if (!disposedValue)
  227. {
  228. if (disposing)
  229. {
  230. DisposeSubject(ref countChanged);
  231. DisposeSubject(ref collectionReset);
  232. DisposeSubject(ref dictionaryAdd);
  233. DisposeSubject(ref dictionaryRemove);
  234. DisposeSubject(ref dictionaryReplace);
  235. }
  236. disposedValue = true;
  237. }
  238. }
  239. public void Dispose()
  240. {
  241. Dispose(true);
  242. }
  243. #endregion
  244. #region Observe
  245. [NonSerialized]
  246. Subject<int> countChanged = null;
  247. public IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false)
  248. {
  249. if (isDisposed) return Observable.Empty<int>();
  250. var subject = countChanged ?? (countChanged = new Subject<int>());
  251. if (notifyCurrentCount)
  252. {
  253. return subject.StartWith(() => this.Count);
  254. }
  255. else
  256. {
  257. return subject;
  258. }
  259. }
  260. [NonSerialized]
  261. Subject<Unit> collectionReset = null;
  262. public IObservable<Unit> ObserveReset()
  263. {
  264. if (isDisposed) return Observable.Empty<Unit>();
  265. return collectionReset ?? (collectionReset = new Subject<Unit>());
  266. }
  267. [NonSerialized]
  268. Subject<DictionaryAddEvent<TKey, TValue>> dictionaryAdd = null;
  269. public IObservable<DictionaryAddEvent<TKey, TValue>> ObserveAdd()
  270. {
  271. if (isDisposed) return Observable.Empty<DictionaryAddEvent<TKey, TValue>>();
  272. return dictionaryAdd ?? (dictionaryAdd = new Subject<DictionaryAddEvent<TKey, TValue>>());
  273. }
  274. [NonSerialized]
  275. Subject<DictionaryRemoveEvent<TKey, TValue>> dictionaryRemove = null;
  276. public IObservable<DictionaryRemoveEvent<TKey, TValue>> ObserveRemove()
  277. {
  278. if (isDisposed) return Observable.Empty<DictionaryRemoveEvent<TKey, TValue>>();
  279. return dictionaryRemove ?? (dictionaryRemove = new Subject<DictionaryRemoveEvent<TKey, TValue>>());
  280. }
  281. [NonSerialized]
  282. Subject<DictionaryReplaceEvent<TKey, TValue>> dictionaryReplace = null;
  283. public IObservable<DictionaryReplaceEvent<TKey, TValue>> ObserveReplace()
  284. {
  285. if (isDisposed) return Observable.Empty<DictionaryReplaceEvent<TKey, TValue>>();
  286. return dictionaryReplace ?? (dictionaryReplace = new Subject<DictionaryReplaceEvent<TKey, TValue>>());
  287. }
  288. #endregion
  289. #region implement explicit
  290. object IDictionary.this[object key]
  291. {
  292. get
  293. {
  294. return this[(TKey)key];
  295. }
  296. set
  297. {
  298. this[(TKey)key] = (TValue)value;
  299. }
  300. }
  301. bool IDictionary.IsFixedSize
  302. {
  303. get
  304. {
  305. return ((IDictionary)inner).IsFixedSize;
  306. }
  307. }
  308. bool IDictionary.IsReadOnly
  309. {
  310. get
  311. {
  312. return ((IDictionary)inner).IsReadOnly;
  313. }
  314. }
  315. bool ICollection.IsSynchronized
  316. {
  317. get
  318. {
  319. return ((IDictionary)inner).IsSynchronized;
  320. }
  321. }
  322. ICollection IDictionary.Keys
  323. {
  324. get
  325. {
  326. return ((IDictionary)inner).Keys;
  327. }
  328. }
  329. object ICollection.SyncRoot
  330. {
  331. get
  332. {
  333. return ((IDictionary)inner).SyncRoot;
  334. }
  335. }
  336. ICollection IDictionary.Values
  337. {
  338. get
  339. {
  340. return ((IDictionary)inner).Values;
  341. }
  342. }
  343. bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
  344. {
  345. get
  346. {
  347. return ((ICollection<KeyValuePair<TKey, TValue>>)inner).IsReadOnly;
  348. }
  349. }
  350. ICollection<TKey> IDictionary<TKey, TValue>.Keys
  351. {
  352. get
  353. {
  354. return inner.Keys;
  355. }
  356. }
  357. ICollection<TValue> IDictionary<TKey, TValue>.Values
  358. {
  359. get
  360. {
  361. return inner.Values;
  362. }
  363. }
  364. void IDictionary.Add(object key, object value)
  365. {
  366. Add((TKey)key, (TValue)value);
  367. }
  368. bool IDictionary.Contains(object key)
  369. {
  370. return ((IDictionary)inner).Contains(key);
  371. }
  372. void ICollection.CopyTo(Array array, int index)
  373. {
  374. ((IDictionary)inner).CopyTo(array, index);
  375. }
  376. #if !UNITY_METRO
  377. public void GetObjectData(SerializationInfo info, StreamingContext context)
  378. {
  379. ((ISerializable)inner).GetObjectData(info, context);
  380. }
  381. public void OnDeserialization(object sender)
  382. {
  383. ((IDeserializationCallback)inner).OnDeserialization(sender);
  384. }
  385. #endif
  386. void IDictionary.Remove(object key)
  387. {
  388. Remove((TKey)key);
  389. }
  390. void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
  391. {
  392. Add((TKey)item.Key, (TValue)item.Value);
  393. }
  394. bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
  395. {
  396. return ((ICollection<KeyValuePair<TKey, TValue>>)inner).Contains(item);
  397. }
  398. void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
  399. {
  400. ((ICollection<KeyValuePair<TKey, TValue>>)inner).CopyTo(array, arrayIndex);
  401. }
  402. IEnumerator<KeyValuePair<TKey, TValue>> IEnumerable<KeyValuePair<TKey, TValue>>.GetEnumerator()
  403. {
  404. return ((ICollection<KeyValuePair<TKey, TValue>>)inner).GetEnumerator();
  405. }
  406. IEnumerator IEnumerable.GetEnumerator()
  407. {
  408. return inner.GetEnumerator();
  409. }
  410. bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
  411. {
  412. TValue v;
  413. if (TryGetValue(item.Key, out v))
  414. {
  415. if (EqualityComparer<TValue>.Default.Equals(v, item.Value))
  416. {
  417. Remove(item.Key);
  418. return true;
  419. }
  420. }
  421. return false;
  422. }
  423. IDictionaryEnumerator IDictionary.GetEnumerator()
  424. {
  425. return ((IDictionary)inner).GetEnumerator();
  426. }
  427. #endregion
  428. }
  429. public static partial class ReactiveDictionaryExtensions
  430. {
  431. public static ReactiveDictionary<TKey, TValue> ToReactiveDictionary<TKey, TValue>(this Dictionary<TKey, TValue> dictionary)
  432. {
  433. return new ReactiveDictionary<TKey, TValue>(dictionary);
  434. }
  435. }
  436. }