StableCompositeDisposable.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace System.Reactive.Disposables
  5. {
  6. /// <summary>
  7. /// Represents a group of disposable resources that are disposed together.
  8. /// </summary>
  9. public abstract class StableCompositeDisposable : ICancelable
  10. {
  11. /// <summary>
  12. /// Creates a new group containing two disposable resources that are disposed together.
  13. /// </summary>
  14. /// <param name="disposable1">The first disposable resoruce to add to the group.</param>
  15. /// <param name="disposable2">The second disposable resoruce to add to the group.</param>
  16. /// <returns>Group of disposable resources that are disposed together.</returns>
  17. public static ICancelable Create(IDisposable disposable1, IDisposable disposable2)
  18. {
  19. if (disposable1 == null)
  20. throw new ArgumentNullException("disposable1");
  21. if (disposable2 == null)
  22. throw new ArgumentNullException("disposable2");
  23. return new Binary(disposable1, disposable2);
  24. }
  25. /// <summary>
  26. /// Creates a new group of disposable resources that are disposed together.
  27. /// </summary>
  28. /// <param name="disposables">Disposable resources to add to the group.</param>
  29. /// <returns>Group of disposable resources that are disposed together.</returns>
  30. public static ICancelable Create(params IDisposable[] disposables)
  31. {
  32. if (disposables == null)
  33. throw new ArgumentNullException("disposables");
  34. return new NAry(disposables);
  35. }
  36. /// <summary>
  37. /// Creates a new group of disposable resources that are disposed together.
  38. /// </summary>
  39. /// <param name="disposables">Disposable resources to add to the group.</param>
  40. /// <returns>Group of disposable resources that are disposed together.</returns>
  41. public static ICancelable Create(IEnumerable<IDisposable> disposables)
  42. {
  43. if (disposables == null)
  44. throw new ArgumentNullException("disposables");
  45. return new NAry(disposables);
  46. }
  47. /// <summary>
  48. /// Disposes all disposables in the group.
  49. /// </summary>
  50. public abstract void Dispose();
  51. /// <summary>
  52. /// Gets a value that indicates whether the object is disposed.
  53. /// </summary>
  54. public abstract bool IsDisposed
  55. {
  56. get;
  57. }
  58. class Binary : StableCompositeDisposable
  59. {
  60. private volatile IDisposable _disposable1;
  61. private volatile IDisposable _disposable2;
  62. public Binary(IDisposable disposable1, IDisposable disposable2)
  63. {
  64. _disposable1 = disposable1;
  65. _disposable2 = disposable2;
  66. }
  67. public override bool IsDisposed
  68. {
  69. get
  70. {
  71. return _disposable1 == null;
  72. }
  73. }
  74. public override void Dispose()
  75. {
  76. #pragma warning disable 0420
  77. var old1 = Interlocked.Exchange(ref _disposable1, null);
  78. #pragma warning restore 0420
  79. if (old1 != null)
  80. {
  81. old1.Dispose();
  82. }
  83. #pragma warning disable 0420
  84. var old2 = Interlocked.Exchange(ref _disposable2, null);
  85. #pragma warning restore 0420
  86. if (old2 != null)
  87. {
  88. old2.Dispose();
  89. }
  90. }
  91. }
  92. class NAry : StableCompositeDisposable
  93. {
  94. private volatile List<IDisposable> _disposables;
  95. public NAry(IDisposable[] disposables)
  96. : this((IEnumerable<IDisposable>)disposables)
  97. {
  98. }
  99. public NAry(IEnumerable<IDisposable> disposables)
  100. {
  101. _disposables = new List<IDisposable>(disposables);
  102. //
  103. // Doing this on the list to avoid duplicate enumeration of disposables.
  104. //
  105. if (_disposables.Contains(null))
  106. throw new ArgumentException(Strings_Core.DISPOSABLES_CANT_CONTAIN_NULL, "disposables");
  107. }
  108. public override bool IsDisposed
  109. {
  110. get
  111. {
  112. return _disposables == null;
  113. }
  114. }
  115. public override void Dispose()
  116. {
  117. #pragma warning disable 0420
  118. var old = Interlocked.Exchange(ref _disposables, null);
  119. #pragma warning restore 0420
  120. if (old != null)
  121. {
  122. foreach (var d in old)
  123. {
  124. d.Dispose();
  125. }
  126. }
  127. }
  128. }
  129. }
  130. }