上海虹口龙之梦项目
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

333 lines
10 KiB

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);
}
}
}