Skip to content

Commit 27cbac6

Browse files
author
Oren Novotny
authored
Merge pull request #979 from dotnet/cherry-pick-832-to-41
Cherry pick 832 to 41
2 parents 6f5aec4 + c19d489 commit 27cbac6

File tree

5 files changed

+115
-11
lines changed

5 files changed

+115
-11
lines changed

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

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System.Reactive.Disposables;
6+
using System.Threading;
67

78
namespace System.Reactive.Linq.ObservableImpl
89
{
@@ -24,7 +25,6 @@ public Finally(IObservable<TSource> source, Action finallyAction)
2425
internal sealed class _ : IdentitySink<TSource>
2526
{
2627
private readonly Action _finallyAction;
27-
2828
private IDisposable _sourceDisposable;
2929

3030
public _(Action finallyAction, IObserver<TSource> observer)
@@ -35,19 +35,43 @@ public _(Action finallyAction, IObserver<TSource> observer)
3535

3636
public override void Run(IObservable<TSource> source)
3737
{
38-
Disposable.SetSingle(ref _sourceDisposable, source.SubscribeSafe(this));
38+
var d = source.SubscribeSafe(this);
39+
40+
if (Interlocked.CompareExchange(ref _sourceDisposable, d, null) == BooleanDisposable.True)
41+
{
42+
// The Dispose(bool) methode was already called before the
43+
// subscription could be assign, hence the subscription
44+
// needs to be diposed here and the action needs to be invoked.
45+
try
46+
{
47+
d.Dispose();
48+
}
49+
finally
50+
{
51+
_finallyAction();
52+
}
53+
}
3954
}
4055

4156
protected override void Dispose(bool disposing)
4257
{
58+
base.Dispose(disposing);
59+
4360
if (disposing)
4461
{
45-
if (Disposable.TryDispose(ref _sourceDisposable))
62+
var d = Interlocked.Exchange(ref _sourceDisposable, BooleanDisposable.True);
63+
if (d != BooleanDisposable.True && d != null)
4664
{
47-
_finallyAction();
65+
try
66+
{
67+
d.Dispose();
68+
}
69+
finally
70+
{
71+
_finallyAction();
72+
}
4873
}
4974
}
50-
base.Dispose(disposing);
5175
}
5276
}
5377
}

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

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,33 +34,37 @@ public _(IObserver<TSource> observer)
3434
public void Run(Using<TSource, TResource> parent)
3535
{
3636
var source = default(IObservable<TSource>);
37+
var disposable = Disposable.Empty;
3738
try
3839
{
3940
var resource = parent._resourceFactory();
4041
if (resource != null)
4142
{
42-
Disposable.SetSingle(ref _disposable, resource);
43+
disposable = resource;
4344
}
4445

4546
source = parent._observableFactory(resource);
4647
}
4748
catch (Exception exception)
4849
{
49-
SetUpstream(Observable.Throw<TSource>(exception).SubscribeSafe(this));
50-
51-
return;
50+
source = Observable.Throw<TSource>(exception);
5251
}
5352

53+
// It is important to set the disposable resource after
54+
// Run(). In the synchronous case this would else dispose
55+
// the the resource before the source subscription.
5456
Run(source);
57+
Disposable.SetSingle(ref _disposable, disposable);
5558
}
5659

5760
protected override void Dispose(bool disposing)
5861
{
62+
base.Dispose(disposing);
63+
5964
if (disposing)
6065
{
6166
Disposable.TryDispose(ref _disposable);
6267
}
63-
base.Dispose(disposing);
6468
}
6569
}
6670
}

Rx.NET/Source/tests/Tests.System.Reactive/Tests/Linq/Observable/FinallyTest.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Reactive;
67
using System.Reactive.Linq;
78
using Microsoft.Reactive.Testing;
89
using Xunit;
@@ -142,5 +143,48 @@ public void Finally_Throw()
142143
);
143144
}
144145

146+
[Fact]
147+
public void Finally_DisposeOrder_Empty()
148+
{
149+
var order = "";
150+
Observable
151+
.Empty<Unit>()
152+
.Finally(() => order += "1")
153+
.Finally(() => order += "2")
154+
.Finally(() => order += "3")
155+
.Subscribe();
156+
157+
Assert.Equal("123", order);
158+
}
159+
160+
[Fact]
161+
public void Finally_DisposeOrder_Return()
162+
{
163+
var order = "";
164+
Observable
165+
.Return(Unit.Default)
166+
.Finally(() => order += "1")
167+
.Finally(() => order += "2")
168+
.Finally(() => order += "3")
169+
.Subscribe();
170+
171+
Assert.Equal("123", order);
172+
}
173+
174+
[Fact]
175+
public void Finally_DisposeOrder_Never()
176+
{
177+
var order = "";
178+
var d = Observable
179+
.Never<Unit>()
180+
.Finally(() => order += "1")
181+
.Finally(() => order += "2")
182+
.Finally(() => order += "3")
183+
.Subscribe();
184+
185+
d.Dispose();
186+
187+
Assert.Equal("123", order);
188+
}
145189
}
146190
}

Rx.NET/Source/tests/Tests.System.Reactive/Tests/Linq/Observable/UsingTest.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
// See the LICENSE file in the project root for more information.
44

55
using System;
6+
using System.Reactive;
7+
using System.Reactive.Disposables;
68
using System.Reactive.Linq;
79
using Microsoft.Reactive.Testing;
810
using ReactiveTests.Dummies;
@@ -295,5 +297,35 @@ public void Using_ThrowResourceUsage()
295297
);
296298
}
297299

300+
[Fact]
301+
public void Using_NestedCompleted()
302+
{
303+
var order = "";
304+
305+
Observable.Using(() => Disposable.Create(() => order += "3"),
306+
_ => Observable.Using(() => Disposable.Create(() => order += "2"),
307+
__ => Observable.Using(() => Disposable.Create(() => order += "1"),
308+
___ => Observable.Return(Unit.Default))))
309+
.Finally(() => order += "4")
310+
.Subscribe();
311+
312+
Assert.Equal("1234", order);
313+
}
314+
315+
[Fact]
316+
public void Using_NestedDisposed()
317+
{
318+
var order = "";
319+
320+
Observable.Using(() => Disposable.Create(() => order += "3"),
321+
_ => Observable.Using(() => Disposable.Create(() => order += "2"),
322+
__ => Observable.Using(() => Disposable.Create(() => order += "1"),
323+
___ => Observable.Never<Unit>())))
324+
.Finally(() => order += "4")
325+
.Subscribe()
326+
.Dispose();
327+
328+
Assert.Equal("1234", order);
329+
}
298330
}
299331
}

Rx.NET/Source/version.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"version": "4.1.5",
2+
"version": "4.1.6",
33
"publicReleaseRefSpec": [
44
"^refs/heads/master$", // we release out of master
55
"^refs/heads/rel/v\\d+\\.\\d+" // we also release branches starting with rel/vN.N

0 commit comments

Comments
 (0)