66
77namespace System . Reactive . Disposables
88{
9+ internal enum TrySetSingleResult
10+ {
11+ Success ,
12+ AlreadyAssigned ,
13+ Disposed
14+ }
15+
916 /// <summary>
1017 /// Provides a set of static methods for creating <see cref="IDisposable"/> objects.
1118 /// </summary>
@@ -54,7 +61,8 @@ public static IDisposable Create(Action dispose)
5461 }
5562
5663 /// <summary>
57- /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.
64+ /// Gets the value stored in <paramref name="fieldRef" /> or a null if
65+ /// <paramref name="fieldRef" /> was already disposed.
5866 /// </summary>
5967 internal static IDisposable GetValue ( ref IDisposable fieldRef )
6068 {
@@ -66,7 +74,8 @@ internal static IDisposable GetValue(ref IDisposable fieldRef)
6674 }
6775
6876 /// <summary>
69- /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.
77+ /// Gets the value stored in <paramref name="fieldRef" /> or a no-op-Disposable if
78+ /// <paramref name="fieldRef" /> was already disposed.
7079 /// </summary>
7180 internal static IDisposable GetValueOrDefault ( ref IDisposable fieldRef )
7281 {
@@ -77,19 +86,46 @@ internal static IDisposable GetValueOrDefault(ref IDisposable fieldRef)
7786 : current ;
7887 }
7988
80- internal static bool TrySetSingle ( ref IDisposable fieldRef , IDisposable value )
89+ /// <summary>
90+ /// Assigns <paramref name="value" /> to <paramref name="fieldRef" />.
91+ /// </summary>
92+ /// <returns>true if <paramref name="fieldRef" /> was assigned to <paramref name="value" /> and has not
93+ /// been assigned before.</returns>
94+ /// <returns>false if <paramref name="fieldRef" /> has been already disposed.</returns>
95+ /// <exception cref="InvalidOperationException"><paramref name="fieldRef" /> has already been assigned a value.</exception>
96+ internal static bool SetSingle ( ref IDisposable fieldRef , IDisposable value )
97+ {
98+ var result = TrySetSingle ( ref fieldRef , value ) ;
99+
100+ if ( result == TrySetSingleResult . AlreadyAssigned )
101+ throw new InvalidOperationException ( Strings_Core . DISPOSABLE_ALREADY_ASSIGNED ) ;
102+
103+ return result == TrySetSingleResult . Success ;
104+ }
105+
106+ /// <summary>
107+ /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />.
108+ /// </summary>
109+ /// <returns>A <see cref="TrySetSingleResult"/> value indicating the outcome of the operation.</returns>
110+ internal static TrySetSingleResult TrySetSingle ( ref IDisposable fieldRef , IDisposable value )
81111 {
82112 var old = Interlocked . CompareExchange ( ref fieldRef , value , null ) ;
83113 if ( old == null )
84- return true ;
114+ return TrySetSingleResult . Success ;
85115
86116 if ( old != BooleanDisposable . True )
87- throw new InvalidOperationException ( Strings_Core . DISPOSABLE_ALREADY_ASSIGNED ) ;
117+ return TrySetSingleResult . AlreadyAssigned ;
88118
89119 value ? . Dispose ( ) ;
90- return false ;
120+ return TrySetSingleResult . Disposed ;
91121 }
92122
123+ /// <summary>
124+ /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />. If <paramref name="fieldRef" />
125+ /// is not disposed and is assigned a different value, it will not be disposed.
126+ /// </summary>
127+ /// <returns>true if <paramref name="value" /> was successfully assigned to <paramref name="fieldRef" />.</returns>
128+ /// <returns>false <paramref name="fieldRef" /> has been disposed.</returns>
93129 internal static bool TrySetMultiple ( ref IDisposable fieldRef , IDisposable value )
94130 {
95131 // Let's read the current value atomically (also prevents reordering).
@@ -118,6 +154,12 @@ internal static bool TrySetMultiple(ref IDisposable fieldRef, IDisposable value)
118154 }
119155 }
120156
157+ /// <summary>
158+ /// Tries to assign <paramref name="value" /> to <paramref name="fieldRef" />. If <paramref name="fieldRef" />
159+ /// is not disposed and is assigned a different value, it will be disposed.
160+ /// </summary>
161+ /// <returns>true if <paramref name="value" /> was successfully assigned to <paramref name="fieldRef" />.</returns>
162+ /// <returns>false <paramref name="fieldRef" /> has been disposed.</returns>
121163 internal static bool TrySetSerial ( ref IDisposable fieldRef , IDisposable value )
122164 {
123165 var copy = Volatile . Read ( ref fieldRef ) ;
@@ -140,6 +182,11 @@ internal static bool TrySetSerial(ref IDisposable fieldRef, IDisposable value)
140182 }
141183 }
142184
185+ /// <summary>
186+ /// Gets a value indicating whether <paramref name="fieldRef" /> has been disposed.
187+ /// </summary>
188+ /// <returns>true if <paramref name="fieldRef" /> has been disposed.</returns>
189+ /// <returns>false if <paramref name="fieldRef" /> has not been disposed.</returns>
143190 internal static bool GetIsDisposed ( ref IDisposable fieldRef )
144191 {
145192 // We use a sentinel value to indicate we've been disposed. This sentinel never leaks
@@ -148,6 +195,11 @@ internal static bool GetIsDisposed(ref IDisposable fieldRef)
148195 return Volatile . Read ( ref fieldRef ) == BooleanDisposable . True ;
149196 }
150197
198+ /// <summary>
199+ /// Tries to dispose <paramref name="fieldRef" />.
200+ /// </summary>
201+ /// <returns>true if <paramref name="fieldRef" /> was not disposed previously and was successfully disposed.</returns>
202+ /// <returns>false if <paramref name="fieldRef" /> was disposed previously.</returns>
151203 internal static bool TryDispose ( ref IDisposable fieldRef )
152204 {
153205 var old = Interlocked . Exchange ( ref fieldRef , BooleanDisposable . True ) ;
0 commit comments