123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- using System;
- using System.Collections.Generic;
- using System.Collections.ObjectModel;
- namespace UniRx
- {
- public struct CollectionAddEvent<T> : IEquatable<CollectionAddEvent<T>>
- {
- public int Index { get; private set; }
- public T Value { get; private set; }
- public CollectionAddEvent(int index, T value)
- :this()
- {
- Index = index;
- Value = value;
- }
- public override string ToString()
- {
- return string.Format("Index:{0} Value:{1}", Index, Value);
- }
- public override int GetHashCode()
- {
- return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(Value) << 2;
- }
- public bool Equals(CollectionAddEvent<T> other)
- {
- return Index.Equals(other.Index) && EqualityComparer<T>.Default.Equals(Value, other.Value);
- }
- }
- public struct CollectionRemoveEvent<T> : IEquatable<CollectionRemoveEvent<T>>
- {
- public int Index { get; private set; }
- public T Value { get; private set; }
- public CollectionRemoveEvent(int index, T value)
- : this()
- {
- Index = index;
- Value = value;
- }
- public override string ToString()
- {
- return string.Format("Index:{0} Value:{1}", Index, Value);
- }
- public override int GetHashCode()
- {
- return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(Value) << 2;
- }
- public bool Equals(CollectionRemoveEvent<T> other)
- {
- return Index.Equals(other.Index) && EqualityComparer<T>.Default.Equals(Value, other.Value);
- }
- }
- public struct CollectionMoveEvent<T> : IEquatable<CollectionMoveEvent<T>>
- {
- public int OldIndex { get; private set; }
- public int NewIndex { get; private set; }
- public T Value { get; private set; }
- public CollectionMoveEvent(int oldIndex, int newIndex, T value)
- : this()
- {
- OldIndex = oldIndex;
- NewIndex = newIndex;
- Value = value;
- }
- public override string ToString()
- {
- return string.Format("OldIndex:{0} NewIndex:{1} Value:{2}", OldIndex, NewIndex, Value);
- }
- public override int GetHashCode()
- {
- return OldIndex.GetHashCode() ^ NewIndex.GetHashCode() << 2 ^ EqualityComparer<T>.Default.GetHashCode(Value) >> 2;
- }
- public bool Equals(CollectionMoveEvent<T> other)
- {
- return OldIndex.Equals(other.OldIndex) && NewIndex.Equals(other.NewIndex) && EqualityComparer<T>.Default.Equals(Value, other.Value);
- }
- }
- public struct CollectionReplaceEvent<T> : IEquatable<CollectionReplaceEvent<T>>
- {
- public int Index { get; private set; }
- public T OldValue { get; private set; }
- public T NewValue { get; private set; }
- public CollectionReplaceEvent(int index, T oldValue, T newValue)
- : this()
- {
- Index = index;
- OldValue = oldValue;
- NewValue = newValue;
- }
- public override string ToString()
- {
- return string.Format("Index:{0} OldValue:{1} NewValue:{2}", Index, OldValue, NewValue);
- }
- public override int GetHashCode()
- {
- return Index.GetHashCode() ^ EqualityComparer<T>.Default.GetHashCode(OldValue) << 2 ^ EqualityComparer<T>.Default.GetHashCode(NewValue) >> 2;
- }
- public bool Equals(CollectionReplaceEvent<T> other)
- {
- return Index.Equals(other.Index)
- && EqualityComparer<T>.Default.Equals(OldValue, other.OldValue)
- && EqualityComparer<T>.Default.Equals(NewValue, other.NewValue);
- }
- }
- // IReadOnlyList<out T> is from .NET 4.5
- public interface IReadOnlyReactiveCollection<T> : IEnumerable<T>
- {
- int Count { get; }
- T this[int index] { get; }
- IObservable<CollectionAddEvent<T>> ObserveAdd();
- IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false);
- IObservable<CollectionMoveEvent<T>> ObserveMove();
- IObservable<CollectionRemoveEvent<T>> ObserveRemove();
- IObservable<CollectionReplaceEvent<T>> ObserveReplace();
- IObservable<Unit> ObserveReset();
- }
- public interface IReactiveCollection<T> : IList<T>, IReadOnlyReactiveCollection<T>
- {
- new int Count { get; }
- new T this[int index] { get; set; }
- void Move(int oldIndex, int newIndex);
- }
- [Serializable]
- public class ReactiveCollection<T> : Collection<T>, IReactiveCollection<T>, IDisposable
- {
- [NonSerialized]
- bool isDisposed = false;
- public ReactiveCollection()
- {
- }
- public ReactiveCollection(IEnumerable<T> collection)
- {
- if (collection == null) throw new ArgumentNullException("collection");
- foreach (var item in collection)
- {
- Add(item);
- }
- }
- public ReactiveCollection(List<T> list)
- : base(list != null ? new List<T>(list) : null)
- {
- }
- protected override void ClearItems()
- {
- var beforeCount = Count;
- base.ClearItems();
- if (collectionReset != null) collectionReset.OnNext(Unit.Default);
- if (beforeCount > 0)
- {
- if (countChanged != null) countChanged.OnNext(Count);
- }
- }
- protected override void InsertItem(int index, T item)
- {
- base.InsertItem(index, item);
- if (collectionAdd != null) collectionAdd.OnNext(new CollectionAddEvent<T>(index, item));
- if (countChanged != null) countChanged.OnNext(Count);
- }
- public void Move(int oldIndex, int newIndex)
- {
- MoveItem(oldIndex, newIndex);
- }
- protected virtual void MoveItem(int oldIndex, int newIndex)
- {
- T item = this[oldIndex];
- base.RemoveItem(oldIndex);
- base.InsertItem(newIndex, item);
- if (collectionMove != null) collectionMove.OnNext(new CollectionMoveEvent<T>(oldIndex, newIndex, item));
- }
- protected override void RemoveItem(int index)
- {
- T item = this[index];
- base.RemoveItem(index);
- if (collectionRemove != null) collectionRemove.OnNext(new CollectionRemoveEvent<T>(index, item));
- if (countChanged != null) countChanged.OnNext(Count);
- }
- protected override void SetItem(int index, T item)
- {
- T oldItem = this[index];
- base.SetItem(index, item);
- if (collectionReplace != null) collectionReplace.OnNext(new CollectionReplaceEvent<T>(index, oldItem, item));
- }
- [NonSerialized]
- Subject<int> countChanged = null;
- public IObservable<int> ObserveCountChanged(bool notifyCurrentCount = false)
- {
- if (isDisposed) return Observable.Empty<int>();
- var subject = countChanged ?? (countChanged = new Subject<int>());
- if (notifyCurrentCount)
- {
- return subject.StartWith(() => this.Count);
- }
- else
- {
- return subject;
- }
- }
- [NonSerialized]
- Subject<Unit> collectionReset = null;
- public IObservable<Unit> ObserveReset()
- {
- if (isDisposed) return Observable.Empty<Unit>();
- return collectionReset ?? (collectionReset = new Subject<Unit>());
- }
- [NonSerialized]
- Subject<CollectionAddEvent<T>> collectionAdd = null;
- public IObservable<CollectionAddEvent<T>> ObserveAdd()
- {
- if (isDisposed) return Observable.Empty<CollectionAddEvent<T>>();
- return collectionAdd ?? (collectionAdd = new Subject<CollectionAddEvent<T>>());
- }
- [NonSerialized]
- Subject<CollectionMoveEvent<T>> collectionMove = null;
- public IObservable<CollectionMoveEvent<T>> ObserveMove()
- {
- if (isDisposed) return Observable.Empty<CollectionMoveEvent<T>>();
- return collectionMove ?? (collectionMove = new Subject<CollectionMoveEvent<T>>());
- }
- [NonSerialized]
- Subject<CollectionRemoveEvent<T>> collectionRemove = null;
- public IObservable<CollectionRemoveEvent<T>> ObserveRemove()
- {
- if (isDisposed) return Observable.Empty<CollectionRemoveEvent<T>>();
- return collectionRemove ?? (collectionRemove = new Subject<CollectionRemoveEvent<T>>());
- }
- [NonSerialized]
- Subject<CollectionReplaceEvent<T>> collectionReplace = null;
- public IObservable<CollectionReplaceEvent<T>> ObserveReplace()
- {
- if (isDisposed) return Observable.Empty<CollectionReplaceEvent<T>>();
- return collectionReplace ?? (collectionReplace = new Subject<CollectionReplaceEvent<T>>());
- }
- void DisposeSubject<TSubject>(ref Subject<TSubject> subject)
- {
- if (subject != null)
- {
- try
- {
- subject.OnCompleted();
- }
- finally
- {
- subject.Dispose();
- subject = null;
- }
- }
- }
- #region IDisposable Support
- private bool disposedValue = false;
- protected virtual void Dispose(bool disposing)
- {
- if (!disposedValue)
- {
- if (disposing)
- {
- DisposeSubject(ref collectionReset);
- DisposeSubject(ref collectionAdd);
- DisposeSubject(ref collectionMove);
- DisposeSubject(ref collectionRemove);
- DisposeSubject(ref collectionReplace);
- DisposeSubject(ref countChanged);
- }
- disposedValue = true;
- }
- }
- public void Dispose()
- {
- Dispose(true);
- }
-
- #endregion
- }
- public static partial class ReactiveCollectionExtensions
- {
- public static ReactiveCollection<T> ToReactiveCollection<T>(this IEnumerable<T> source)
- {
- return new ReactiveCollection<T>(source);
- }
- }
- }
|