// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the Apache 2.0 License. // See the LICENSE file in the project root for more information. using System.Collections; using System.Collections.Generic; using System.Reactive.Disposables; using System.Reactive.Linq; using System.Reactive.Subjects; namespace System.Reactive { // CONSIDER: Deprecate this functionality or invest in an asynchronous variant. /// /// Represents an object that retains the elements of the observable sequence and signals the end of the sequence. /// /// The type of elements received from the source sequence. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "By design; Observable suffix takes precedence.")] [Experimental] public class ListObservable : IList, IObservable { private readonly IDisposable subscription; private readonly AsyncSubject subject = new AsyncSubject(); private readonly List results = new List(); /// /// Constructs an object that retains the values of source and signals the end of the sequence. /// /// The observable sequence whose elements will be retained in the list. /// is null. public ListObservable(IObservable source) { if (source == null) throw new ArgumentNullException(nameof(source)); subscription = source.Subscribe(results.Add, subject.OnError, subject.OnCompleted); } private void Wait() { subject.DefaultIfEmpty().Wait(); } /// /// Returns the last value of the observable sequence. /// public T Value { get { Wait(); if (results.Count == 0) { throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS); } return results[results.Count - 1]; } } /// /// Determines the index of a specific item in the ListObservable. /// /// The element to determine the index for. /// The index of the specified item in the list; -1 if not found. public int IndexOf(T item) { Wait(); return results.IndexOf(item); } /// /// Inserts an item to the ListObservable at the specified index. /// /// The index to insert the item at. /// The item to insert in the list. public void Insert(int index, T item) { Wait(); results.Insert(index, item); } /// /// Removes the ListObservable item at the specified index. /// /// The index of the item to remove. public void RemoveAt(int index) { Wait(); results.RemoveAt(index); } /// /// Gets or sets the element at the specified index. /// /// The index of the item to retrieve or set. public T this[int index] { get { Wait(); return results[index]; } set { Wait(); results[index] = value; } } /// /// Adds an item to the ListObservable. /// /// The item to add to the list. public void Add(T item) { Wait(); results.Add(item); } /// /// Removes all items from the ListObservable. /// public void Clear() { Wait(); results.Clear(); } /// /// Determines whether the ListObservable contains a specific value. /// /// The item to search for in the list. /// true if found; false otherwise. public bool Contains(T item) { Wait(); return results.Contains(item); } /// /// Copies the elements of the ListObservable to an System.Array, starting at a particular System.Array index. /// /// The array to copy elements to. /// The start index in the array to start copying elements to. public void CopyTo(T[] array, int arrayIndex) { Wait(); results.CopyTo(array, arrayIndex); } /// /// Gets the number of elements contained in the ListObservable. /// public int Count { get { Wait(); return results.Count; } } /// /// Gets a value that indicates whether the ListObservable is read-only. /// public bool IsReadOnly { get { return false; } } /// /// Removes the first occurrence of a specific object from the ListObservable. /// /// The item to remove from the list. /// true if the item was found; false otherwise. public bool Remove(T item) { Wait(); return results.Remove(item); } /// /// Returns an enumerator that iterates through the collection. /// /// Enumerator over the list. public IEnumerator GetEnumerator() { Wait(); return results.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); /// /// Subscribes an observer to the ListObservable which will be notified upon completion. /// /// The observer to send completion or error messages to. /// The disposable resource that can be used to unsubscribe. /// is null. public IDisposable Subscribe(IObserver observer) { if (observer == null) throw new ArgumentNullException(nameof(observer)); return StableCompositeDisposable.Create(subscription, subject.Subscribe(observer)); } } }