ソースを参照

Save two allocations in the finally operator

Peter Wehrfritz 7 年 前
コミット
31e6aa86bb
1 ファイル変更30 行追加4 行削除
  1. 30 4
      Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs

+ 30 - 4
Rx.NET/Source/src/System.Reactive/Linq/Observable/Finally.cs

@@ -3,6 +3,7 @@
 // See the LICENSE file in the project root for more information. 
 
 using System.Reactive.Disposables;
+using System.Threading;
 
 namespace System.Reactive.Linq.ObservableImpl
 {
@@ -24,6 +25,7 @@ namespace System.Reactive.Linq.ObservableImpl
         internal sealed class _ : IdentitySink<TSource>
         {
             private readonly Action _finallyAction;
+            private IDisposable _sourceDisposable;
 
             public _(Action finallyAction, IObserver<TSource> observer)
                 : base(observer)
@@ -33,19 +35,43 @@ namespace System.Reactive.Linq.ObservableImpl
 
             public override void Run(IObservable<TSource> source)
             {
-                var subscription = source.SubscribeSafe(this);
+                var d = source.SubscribeSafe(this);
 
-                SetUpstream(Disposable.Create(() =>
+                if (Interlocked.CompareExchange(ref _sourceDisposable, d, null) == BooleanDisposable.True)
                 {
+                    // The Dispose(bool) methode was already called before the
+                    // subscription could be assign, hence the subscription
+                    // needs to be diposed here and the action needs to be invoked.
                     try
                     {
-                        subscription.Dispose();
+                        d.Dispose();
                     }
                     finally
                     {
                         _finallyAction();
                     }
-                }));
+                }
+            }
+
+            protected override void Dispose(bool disposing)
+            {
+                base.Dispose(disposing);
+
+                if (disposing)
+                {
+                    var d = Interlocked.Exchange(ref _sourceDisposable, BooleanDisposable.True);
+                    if (d != BooleanDisposable.True && d != null)
+                    {
+                        try
+                        {
+                            d.Dispose();
+                        }
+                        finally
+                        {
+                            _finallyAction();
+                        }
+                    }
+                }
             }
         }
     }