Quellcode durchsuchen

TrySetSingle should be called SetSingle since it can throw, TrySetSingle however remains and returns a more meaningful result. Added more docs. (#557)

Daniel C. Weber vor 7 Jahren
Ursprung
Commit
673dd5ac98

+ 2 - 2
Rx.NET/Source/src/System.Reactive/Concurrency/DefaultScheduler.cs

@@ -32,14 +32,14 @@ namespace System.Reactive.Concurrency
             {
                 if (!Disposable.GetIsDisposed(ref _cancelRunDisposable))
                 {
-                    Disposable.TrySetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
+                    Disposable.SetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
                 }
             }
 
             public IDisposable CancelQueueDisposable
             {
                 get => Disposable.GetValue(ref _cancelQueueDisposable);
-                set => Disposable.TrySetSingle(ref _cancelQueueDisposable, value);
+                set => Disposable.SetSingle(ref _cancelQueueDisposable, value);
             }
 
             public void Dispose()

+ 1 - 1
Rx.NET/Source/src/System.Reactive/Concurrency/ThreadPoolScheduler.cs

@@ -34,7 +34,7 @@ namespace System.Reactive.Concurrency
             {
                 if (!Disposable.GetIsDisposed(ref _cancelRunDisposable))
                 {
-                    Disposable.TrySetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
+                    Disposable.SetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
                 }
             }
 

+ 58 - 6
Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs

@@ -6,6 +6,13 @@ using System.Threading;
 
 namespace System.Reactive.Disposables
 {
+    internal enum TrySetSingleResult
+    {
+        Success,
+        AlreadyAssigned,
+        Disposed
+    }
+
     /// <summary>
     /// Provides a set of static methods for creating <see cref="IDisposable"/> objects.
     /// </summary>
@@ -54,7 +61,8 @@ namespace System.Reactive.Disposables
         }
 
         /// <summary>
-        /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.
+        /// Gets the value stored in <paramref name="fieldRef" /> or a null if
+        /// <paramref name="fieldRef" /> was already disposed.
         /// </summary>
         internal static IDisposable GetValue(ref IDisposable fieldRef)
         {
@@ -66,7 +74,8 @@ namespace System.Reactive.Disposables
         }
 
         /// <summary>
-        /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.
+        /// Gets the value stored in <paramref name="fieldRef" /> or a no-op-Disposable if
+        /// <paramref name="fieldRef" /> was already disposed.
         /// </summary>
         internal static IDisposable GetValueOrDefault(ref IDisposable fieldRef)
         {
@@ -77,19 +86,46 @@ namespace System.Reactive.Disposables
                 : current;
         }
 
-        internal static bool TrySetSingle(ref IDisposable fieldRef, IDisposable value)
+        /// <summary>
+        /// Assigns <paramref name="value" /> to <paramref name="fieldRef" />.
+        /// </summary>
+        /// <returns>true if <paramref name="fieldRef" /> was assigned to <paramref name="value" /> and has not
+        /// been assigned before.</returns>
+        /// <returns>false if <paramref name="fieldRef" /> has been already disposed.</returns>
+        /// <exception cref="InvalidOperationException"><paramref name="fieldRef" /> has already been assigned a value.</exception>
+        internal static bool SetSingle(ref IDisposable fieldRef, IDisposable value)
+        {
+            var result = TrySetSingle(ref fieldRef, value);
+
+            if (result == TrySetSingleResult.AlreadyAssigned)
+                throw new InvalidOperationException(Strings_Core.DISPOSABLE_ALREADY_ASSIGNED);
+
+            return result == TrySetSingleResult.Success;
+        }
+
+        /// <summary>
+        /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />.
+        /// </summary>
+        /// <returns>A <see cref="TrySetSingleResult"/> value indicating the outcome of the operation.</returns>
+        internal static TrySetSingleResult TrySetSingle(ref IDisposable fieldRef, IDisposable value)
         {
             var old = Interlocked.CompareExchange(ref fieldRef, value, null);
             if (old == null)
-                return true;
+                return TrySetSingleResult.Success;
 
             if (old != BooleanDisposable.True)
-                throw new InvalidOperationException(Strings_Core.DISPOSABLE_ALREADY_ASSIGNED);
+                return TrySetSingleResult.AlreadyAssigned;
 
             value?.Dispose();
-            return false;
+            return TrySetSingleResult.Disposed;
         }
 
+        /// <summary>
+        /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />. If <paramref name="fieldRef" />
+        /// is not disposed and is assigned a different value, it will not be disposed.
+        /// </summary>
+        /// <returns>true if <paramref name="value" /> was successfully assigned to <paramref name="fieldRef" />.</returns>
+        /// <returns>false <paramref name="fieldRef" /> has been disposed.</returns>
         internal static bool TrySetMultiple(ref IDisposable fieldRef, IDisposable value)
         {
             // Let's read the current value atomically (also prevents reordering).
@@ -118,6 +154,12 @@ namespace System.Reactive.Disposables
             }
         }
 
+        /// <summary>
+        /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />. If <paramref name="fieldRef" />
+        /// is not disposed and is assigned a different value, it will be disposed.
+        /// </summary>
+        /// <returns>true if <paramref name="value" /> was successfully assigned to <paramref name="fieldRef" />.</returns>
+        /// <returns>false <paramref name="fieldRef" /> has been disposed.</returns>
         internal static bool TrySetSerial(ref IDisposable fieldRef, IDisposable value)
         {
             var copy = Volatile.Read(ref fieldRef);
@@ -140,6 +182,11 @@ namespace System.Reactive.Disposables
             }
         }
 
+        /// <summary>
+        /// Gets a value indicating whether <paramref name="fieldRef" /> has been disposed.
+        /// </summary>
+        /// <returns>true if <paramref name="fieldRef" /> has been disposed.</returns>
+        /// <returns>false if <paramref name="fieldRef" /> has not been disposed.</returns>
         internal static bool GetIsDisposed(ref IDisposable fieldRef)
         {
             // We use a sentinel value to indicate we've been disposed. This sentinel never leaks
@@ -148,6 +195,11 @@ namespace System.Reactive.Disposables
             return Volatile.Read(ref fieldRef) == BooleanDisposable.True;
         }
 
+        /// <summary>
+        /// Tries to dispose <paramref name="fieldRef" />. 
+        /// </summary>
+        /// <returns>true if <paramref name="fieldRef" /> was not disposed previously and was successfully disposed.</returns>
+        /// <returns>false if <paramref name="fieldRef" /> was disposed previously.</returns>
         internal static bool TryDispose(ref IDisposable fieldRef)
         {
             var old = Interlocked.Exchange(ref fieldRef, BooleanDisposable.True);

+ 1 - 1
Rx.NET/Source/src/System.Reactive/Disposables/SingleAssignmentDisposable.cs

@@ -33,7 +33,7 @@ namespace System.Reactive.Disposables
         public IDisposable Disposable
         {
             get => Disposables.Disposable.GetValueOrDefault(ref _current);
-            set => Disposables.Disposable.TrySetSingle(ref _current, value);
+            set => Disposables.Disposable.SetSingle(ref _current, value);
         }
 
         /// <summary>

+ 2 - 2
Rx.NET/Source/src/System.Reactive/Linq/Observable/TakeUntil.cs

@@ -37,8 +37,8 @@ namespace System.Reactive.Linq.ObservableImpl
 
             public IDisposable Run(TakeUntil<TSource, TOther> parent)
             {
-                Disposable.TrySetSingle(ref _otherDisposable, parent._other.Subscribe(new OtherObserver(this)));
-                Disposable.TrySetSingle(ref _mainDisposable, parent._source.Subscribe(this));
+                Disposable.SetSingle(ref _otherDisposable, parent._other.Subscribe(new OtherObserver(this)));
+                Disposable.SetSingle(ref _mainDisposable, parent._source.Subscribe(this));
 
                 return this;
             }