// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading;
namespace System.Reactive.Disposables
{
///
/// Represents a group of disposable resources that are disposed together.
///
public abstract class StableCompositeDisposable : ICancelable
{
///
/// Creates a new group containing two disposable resources that are disposed together.
///
/// The first disposable resoruce to add to the group.
/// The second disposable resoruce to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
{
if (disposable1 == null)
throw new ArgumentNullException("disposable1");
if (disposable2 == null)
throw new ArgumentNullException("disposable2");
return new Binary(disposable1, disposable2);
}
///
/// Creates a new group of disposable resources that are disposed together.
///
/// Disposable resources to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(params IDisposable[] disposables)
{
if (disposables == null)
throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
///
/// Creates a new group of disposable resources that are disposed together.
///
/// Disposable resources to add to the group.
/// Group of disposable resources that are disposed together.
public static ICancelable Create(IEnumerable disposables)
{
if (disposables == null)
throw new ArgumentNullException("disposables");
return new NAry(disposables);
}
///
/// Disposes all disposables in the group.
///
public abstract void Dispose();
///
/// Gets a value that indicates whether the object is disposed.
///
public abstract bool IsDisposed
{
get;
}
class Binary : StableCompositeDisposable
{
private volatile IDisposable _disposable1;
private volatile IDisposable _disposable2;
public Binary(IDisposable disposable1, IDisposable disposable2)
{
_disposable1 = disposable1;
_disposable2 = disposable2;
}
public override bool IsDisposed
{
get
{
return _disposable1 == null;
}
}
public override void Dispose()
{
#pragma warning disable 0420
var old1 = Interlocked.Exchange(ref _disposable1, null);
#pragma warning restore 0420
if (old1 != null)
{
old1.Dispose();
}
#pragma warning disable 0420
var old2 = Interlocked.Exchange(ref _disposable2, null);
#pragma warning restore 0420
if (old2 != null)
{
old2.Dispose();
}
}
}
class NAry : StableCompositeDisposable
{
private volatile List _disposables;
public NAry(IDisposable[] disposables)
: this((IEnumerable)disposables)
{
}
public NAry(IEnumerable disposables)
{
_disposables = new List(disposables);
//
// Doing this on the list to avoid duplicate enumeration of disposables.
//
if (_disposables.Contains(null))
throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
}
public override bool IsDisposed
{
get
{
return _disposables == null;
}
}
public override void Dispose()
{
#pragma warning disable 0420
var old = Interlocked.Exchange(ref _disposables, null);
#pragma warning restore 0420
if (old != null)
{
foreach (var d in old)
{
d.Dispose();
}
}
}
}
}
}