A game framework written with osu! in mind.
at master 90 lines 2.9 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using System.Collections; 6using System.Collections.Generic; 7using JetBrains.Annotations; 8 9namespace osu.Framework.Lists 10{ 11 /// <summary> 12 /// A wrapper for an array that provides notifications when elements are changed. 13 /// </summary> 14 /// <typeparam name="T">The type of elements stored in the array.</typeparam> 15 public class ObservableArray<T> : IReadOnlyList<T>, IEquatable<ObservableArray<T>>, INotifyArrayChanged 16 { 17 /// <summary> 18 /// Invoked when an element of the array is changed via <see cref="this[int]"/>. 19 /// </summary> 20 public event Action ArrayElementChanged; 21 22 [NotNull] 23 private readonly T[] wrappedArray; 24 25 public ObservableArray(T[] arrayToWrap) 26 { 27 wrappedArray = arrayToWrap ?? throw new ArgumentNullException(nameof(arrayToWrap)); 28 } 29 30 public IEnumerator<T> GetEnumerator() 31 { 32 return ((IEnumerable<T>)wrappedArray).GetEnumerator(); 33 } 34 35 IEnumerator IEnumerable.GetEnumerator() 36 { 37 return wrappedArray.GetEnumerator(); 38 } 39 40 public bool Equals(ObservableArray<T> other) 41 { 42 if (ReferenceEquals(null, other)) return false; 43 if (ReferenceEquals(this, other)) return true; 44 45 return wrappedArray == other.wrappedArray; 46 } 47 48 public override bool Equals(object obj) 49 { 50 if (ReferenceEquals(null, obj)) return false; 51 if (ReferenceEquals(this, obj)) return true; 52 53 return obj.GetType() == GetType() && Equals((ObservableArray<T>)obj); 54 } 55 56 public override int GetHashCode() 57 { 58 return HashCode.Combine(wrappedArray); 59 } 60 61 public int Count => wrappedArray.Length; 62 63 public T this[int index] 64 { 65 get => wrappedArray[index]; 66 set 67 { 68 if (EqualityComparer<T>.Default.Equals(wrappedArray[index], value)) 69 return; 70 71 var previousValue = wrappedArray[index]; 72 if (previousValue is INotifyArrayChanged previousNotifier) 73 previousNotifier.ArrayElementChanged -= OnArrayElementChanged; 74 75 wrappedArray[index] = value; 76 if (value is INotifyArrayChanged notifier) 77 notifier.ArrayElementChanged += OnArrayElementChanged; 78 79 OnArrayElementChanged(); 80 } 81 } 82 83 protected void OnArrayElementChanged() 84 { 85 ArrayElementChanged?.Invoke(); 86 } 87 88 public static implicit operator ObservableArray<T>(T[] source) => source == null ? null : new ObservableArray<T>(source); 89 } 90}