Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/rx.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'Rx.NET/System.Reactive.Core/Reactive/Disposables/RefCountDisposable.cs')
-rw-r--r--Rx.NET/System.Reactive.Core/Reactive/Disposables/RefCountDisposable.cs131
1 files changed, 131 insertions, 0 deletions
diff --git a/Rx.NET/System.Reactive.Core/Reactive/Disposables/RefCountDisposable.cs b/Rx.NET/System.Reactive.Core/Reactive/Disposables/RefCountDisposable.cs
new file mode 100644
index 0000000..9bd0407
--- /dev/null
+++ b/Rx.NET/System.Reactive.Core/Reactive/Disposables/RefCountDisposable.cs
@@ -0,0 +1,131 @@
+// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
+
+using System.Threading;
+
+namespace System.Reactive.Disposables
+{
+ /// <summary>
+ /// Represents a disposable resource that only disposes its underlying disposable resource when all <see cref="GetDisposable">dependent disposable objects</see> have been disposed.
+ /// </summary>
+ public sealed class RefCountDisposable : ICancelable
+ {
+ private readonly object _gate = new object();
+ private IDisposable _disposable;
+ private bool _isPrimaryDisposed;
+ private int _count;
+
+ /// <summary>
+ /// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.RefCountDisposable"/> class with the specified disposable.
+ /// </summary>
+ /// <param name="disposable">Underlying disposable.</param>
+ /// <exception cref="ArgumentNullException"><paramref name="disposable"/> is null.</exception>
+ public RefCountDisposable(IDisposable disposable)
+ {
+ if (disposable == null)
+ throw new ArgumentNullException("disposable");
+
+ _disposable = disposable;
+ _isPrimaryDisposed = false;
+ _count = 0;
+ }
+
+ /// <summary>
+ /// Gets a value that indicates whether the object is disposed.
+ /// </summary>
+ public bool IsDisposed
+ {
+ get { return _disposable == null; }
+ }
+
+ /// <summary>
+ /// Returns a dependent disposable that when disposed decreases the refcount on the underlying disposable.
+ /// </summary>
+ /// <returns>A dependent disposable contributing to the reference count that manages the underlying disposable's lifetime.</returns>
+ [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "Backward compat + non-trivial work for a property getter.")]
+ public IDisposable GetDisposable()
+ {
+ lock (_gate)
+ {
+ if (_disposable == null)
+ {
+ return Disposable.Empty;
+ }
+ else
+ {
+ _count++;
+ return new InnerDisposable(this);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Disposes the underlying disposable only when all dependent disposables have been disposed.
+ /// </summary>
+ public void Dispose()
+ {
+ var disposable = default(IDisposable);
+ lock (_gate)
+ {
+ if (_disposable != null)
+ {
+ if (!_isPrimaryDisposed)
+ {
+ _isPrimaryDisposed = true;
+
+ if (_count == 0)
+ {
+ disposable = _disposable;
+ _disposable = null;
+ }
+ }
+ }
+ }
+
+ if (disposable != null)
+ disposable.Dispose();
+ }
+
+ private void Release()
+ {
+ var disposable = default(IDisposable);
+ lock (_gate)
+ {
+ if (_disposable != null)
+ {
+ _count--;
+
+ System.Diagnostics.Debug.Assert(_count >= 0);
+
+ if (_isPrimaryDisposed)
+ {
+ if (_count == 0)
+ {
+ disposable = _disposable;
+ _disposable = null;
+ }
+ }
+ }
+ }
+
+ if (disposable != null)
+ disposable.Dispose();
+ }
+
+ sealed class InnerDisposable : IDisposable
+ {
+ private RefCountDisposable _parent;
+
+ public InnerDisposable(RefCountDisposable parent)
+ {
+ _parent = parent;
+ }
+
+ public void Dispose()
+ {
+ var parent = Interlocked.Exchange(ref _parent, null);
+ if (parent != null)
+ parent.Release();
+ }
+ }
+ }
+}