// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. using System; using System.Collections; using System.Collections.Generic; using JetBrains.Annotations; namespace osu.Framework.Lists { /// /// A wrapper for an array that provides notifications when elements are changed. /// /// The type of elements stored in the array. public class ObservableArray : IReadOnlyList, IEquatable>, INotifyArrayChanged { /// /// Invoked when an element of the array is changed via . /// public event Action ArrayElementChanged; [NotNull] private readonly T[] wrappedArray; public ObservableArray(T[] arrayToWrap) { wrappedArray = arrayToWrap ?? throw new ArgumentNullException(nameof(arrayToWrap)); } public IEnumerator GetEnumerator() { return ((IEnumerable)wrappedArray).GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return wrappedArray.GetEnumerator(); } public bool Equals(ObservableArray other) { if (ReferenceEquals(null, other)) return false; if (ReferenceEquals(this, other)) return true; return wrappedArray == other.wrappedArray; } public override bool Equals(object obj) { if (ReferenceEquals(null, obj)) return false; if (ReferenceEquals(this, obj)) return true; return obj.GetType() == GetType() && Equals((ObservableArray)obj); } public override int GetHashCode() { return HashCode.Combine(wrappedArray); } public int Count => wrappedArray.Length; public T this[int index] { get => wrappedArray[index]; set { if (EqualityComparer.Default.Equals(wrappedArray[index], value)) return; var previousValue = wrappedArray[index]; if (previousValue is INotifyArrayChanged previousNotifier) previousNotifier.ArrayElementChanged -= OnArrayElementChanged; wrappedArray[index] = value; if (value is INotifyArrayChanged notifier) notifier.ArrayElementChanged += OnArrayElementChanged; OnArrayElementChanged(); } } protected void OnArrayElementChanged() { ArrayElementChanged?.Invoke(); } public static implicit operator ObservableArray(T[] source) => source == null ? null : new ObservableArray(source); } }