Skip to content

Commit 673dd5a

Browse files
authored
TrySetSingle should be called SetSingle since it can throw, TrySetSingle however remains and returns a more meaningful result. Added more docs. (#557)
1 parent 96e7ce3 commit 673dd5a

File tree

5 files changed

+64
-12
lines changed

5 files changed

+64
-12
lines changed

Rx.NET/Source/src/System.Reactive/Concurrency/DefaultScheduler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,14 @@ public void Run()
3232
{
3333
if (!Disposable.GetIsDisposed(ref _cancelRunDisposable))
3434
{
35-
Disposable.TrySetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
35+
Disposable.SetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
3636
}
3737
}
3838

3939
public IDisposable CancelQueueDisposable
4040
{
4141
get => Disposable.GetValue(ref _cancelQueueDisposable);
42-
set => Disposable.TrySetSingle(ref _cancelQueueDisposable, value);
42+
set => Disposable.SetSingle(ref _cancelQueueDisposable, value);
4343
}
4444

4545
public void Dispose()

Rx.NET/Source/src/System.Reactive/Concurrency/ThreadPoolScheduler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public void Run()
3434
{
3535
if (!Disposable.GetIsDisposed(ref _cancelRunDisposable))
3636
{
37-
Disposable.TrySetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
37+
Disposable.SetSingle(ref _cancelRunDisposable, _action(_scheduler, _state));
3838
}
3939
}
4040

Rx.NET/Source/src/System.Reactive/Disposables/Disposable.cs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,13 @@
66

77
namespace 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);

Rx.NET/Source/src/System.Reactive/Disposables/SingleAssignmentDisposable.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public SingleAssignmentDisposable()
3333
public IDisposable Disposable
3434
{
3535
get => Disposables.Disposable.GetValueOrDefault(ref _current);
36-
set => Disposables.Disposable.TrySetSingle(ref _current, value);
36+
set => Disposables.Disposable.SetSingle(ref _current, value);
3737
}
3838

3939
/// <summary>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@ public _(IObserver<TSource> observer, IDisposable cancel)
3737

3838
public IDisposable Run(TakeUntil<TSource, TOther> parent)
3939
{
40-
Disposable.TrySetSingle(ref _otherDisposable, parent._other.Subscribe(new OtherObserver(this)));
41-
Disposable.TrySetSingle(ref _mainDisposable, parent._source.Subscribe(this));
40+
Disposable.SetSingle(ref _otherDisposable, parent._other.Subscribe(new OtherObserver(this)));
41+
Disposable.SetSingle(ref _mainDisposable, parent._source.Subscribe(this));
4242

4343
return this;
4444
}

0 commit comments

Comments
 (0)