1
0

ListObservable.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Reactive.Disposables;
  5. using System.Reactive.Linq;
  6. using System.Reactive.Subjects;
  7. namespace System.Reactive
  8. {
  9. /// <summary>
  10. /// Represents an object that retains the elements of the observable sequence and signals the end of the sequence.
  11. /// </summary>
  12. /// <typeparam name="T">The type of elements received from the source sequence.</typeparam>
  13. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix", Justification = "By design; Observable suffix takes precedence.")]
  14. [Experimental]
  15. public class ListObservable<T> : IList<T>, IObservable<object>
  16. {
  17. IDisposable subscription;
  18. AsyncSubject<object> subject = new AsyncSubject<object>();
  19. List<T> results = new List<T>();
  20. /// <summary>
  21. /// Constructs an object that retains the values of source and signals the end of the sequence.
  22. /// </summary>
  23. /// <param name="source">The observable sequence whose elements will be retained in the list.</param>
  24. /// <exception cref="ArgumentNullException"><paramref name="source"/> is null.</exception>
  25. public ListObservable(IObservable<T> source)
  26. {
  27. if (source == null)
  28. throw new ArgumentNullException("source");
  29. subscription = source.Subscribe(results.Add, subject.OnError, subject.OnCompleted);
  30. }
  31. void Wait()
  32. {
  33. subject.DefaultIfEmpty().Wait();
  34. }
  35. /// <summary>
  36. /// Returns the last value of the observable sequence.
  37. /// </summary>
  38. public T Value
  39. {
  40. get
  41. {
  42. Wait();
  43. if (results.Count == 0)
  44. throw new InvalidOperationException(Strings_Linq.NO_ELEMENTS);
  45. return results[results.Count - 1];
  46. }
  47. }
  48. /// <summary>
  49. /// Determines the index of a specific item in the ListObservable.
  50. /// </summary>
  51. /// <param name="item">The element to determine the index for.</param>
  52. /// <returns>The index of the specified item in the list; -1 if not found.</returns>
  53. public int IndexOf(T item)
  54. {
  55. Wait();
  56. return results.IndexOf(item);
  57. }
  58. /// <summary>
  59. /// Inserts an item to the ListObservable at the specified index.
  60. /// </summary>
  61. /// <param name="index">The index to insert the item at.</param>
  62. /// <param name="item">The item to insert in the list.</param>
  63. public void Insert(int index, T item)
  64. {
  65. Wait();
  66. results.Insert(index, item);
  67. }
  68. /// <summary>
  69. /// Removes the ListObservable item at the specified index.
  70. /// </summary>
  71. /// <param name="index">The index of the item to remove.</param>
  72. public void RemoveAt(int index)
  73. {
  74. Wait();
  75. results.RemoveAt(index);
  76. }
  77. /// <summary>
  78. /// Gets or sets the element at the specified index.
  79. /// </summary>
  80. /// <param name="index">The index of the item to retrieve or set.</param>
  81. public T this[int index]
  82. {
  83. get
  84. {
  85. Wait();
  86. return results[index];
  87. }
  88. set
  89. {
  90. Wait();
  91. results[index] = value;
  92. }
  93. }
  94. /// <summary>
  95. /// Adds an item to the ListObservable.
  96. /// </summary>
  97. /// <param name="item">The item to add to the list.</param>
  98. public void Add(T item)
  99. {
  100. Wait();
  101. results.Add(item);
  102. }
  103. /// <summary>
  104. /// Removes all items from the ListObservable.
  105. /// </summary>
  106. public void Clear()
  107. {
  108. Wait();
  109. results.Clear();
  110. }
  111. /// <summary>
  112. /// Determines whether the ListObservable contains a specific value.
  113. /// </summary>
  114. /// <param name="item">The item to search for in the list.</param>
  115. /// <returns>true if found; false otherwise.</returns>
  116. public bool Contains(T item)
  117. {
  118. Wait();
  119. return results.Contains(item);
  120. }
  121. /// <summary>
  122. /// Copies the elements of the ListObservable to an System.Array, starting at a particular System.Array index.
  123. /// </summary>
  124. /// <param name="array">The array to copy elements to.</param>
  125. /// <param name="arrayIndex">The start index in the array to start copying elements to.</param>
  126. public void CopyTo(T[] array, int arrayIndex)
  127. {
  128. Wait();
  129. results.CopyTo(array, arrayIndex);
  130. }
  131. /// <summary>
  132. /// Gets the number of elements contained in the ListObservable.
  133. /// </summary>
  134. public int Count
  135. {
  136. get
  137. {
  138. Wait();
  139. return results.Count;
  140. }
  141. }
  142. /// <summary>
  143. /// Gets a value that indicates whether the ListObservable is read-only.
  144. /// </summary>
  145. public bool IsReadOnly
  146. {
  147. get { return false; }
  148. }
  149. /// <summary>
  150. /// Removes the first occurrence of a specific object from the ListObservable.
  151. /// </summary>
  152. /// <param name="item">The item to remove from the list.</param>
  153. /// <returns>true if the item was found; false otherwise.</returns>
  154. public bool Remove(T item)
  155. {
  156. Wait();
  157. return results.Remove(item);
  158. }
  159. /// <summary>
  160. /// Returns an enumerator that iterates through the collection.
  161. /// </summary>
  162. /// <returns>Enumerator over the list.</returns>
  163. public IEnumerator<T> GetEnumerator()
  164. {
  165. Wait();
  166. return results.GetEnumerator();
  167. }
  168. IEnumerator IEnumerable.GetEnumerator()
  169. {
  170. return this.GetEnumerator();
  171. }
  172. /// <summary>
  173. /// Subscribes an observer to the ListObservable which will be notified upon completion.
  174. /// </summary>
  175. /// <param name="observer">The observer to send completion or error messages to.</param>
  176. /// <returns>The disposable resource that can be used to unsubscribe.</returns>
  177. /// <exception cref="ArgumentNullException"><paramref name="observer"/> is null.</exception>
  178. public IDisposable Subscribe(IObserver<object> observer)
  179. {
  180. if (observer == null)
  181. throw new ArgumentNullException("observer");
  182. return new CompositeDisposable(subscription, subject.Subscribe(observer));
  183. }
  184. }
  185. }