StableCompositeDisposable.cs 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Threading;
  4. namespace UniRx
  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) throw new ArgumentNullException("disposable1");
  20. if (disposable2 == null) throw new ArgumentNullException("disposable2");
  21. return new Binary(disposable1, disposable2);
  22. }
  23. /// <summary>
  24. /// Creates a new group containing three disposable resources that are disposed together.
  25. /// </summary>
  26. /// <param name="disposable1">The first disposable resoruce to add to the group.</param>
  27. /// <param name="disposable2">The second disposable resoruce to add to the group.</param>
  28. /// <param name="disposable3">The third disposable resoruce to add to the group.</param>
  29. /// <returns>Group of disposable resources that are disposed together.</returns>
  30. public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
  31. {
  32. if (disposable1 == null) throw new ArgumentNullException("disposable1");
  33. if (disposable2 == null) throw new ArgumentNullException("disposable2");
  34. if (disposable3 == null) throw new ArgumentNullException("disposable3");
  35. return new Trinary(disposable1, disposable2, disposable3);
  36. }
  37. /// <summary>
  38. /// Creates a new group containing four disposable resources that are disposed together.
  39. /// </summary>
  40. /// <param name="disposable1">The first disposable resoruce to add to the group.</param>
  41. /// <param name="disposable2">The second disposable resoruce to add to the group.</param>
  42. /// <param name="disposable3">The three disposable resoruce to add to the group.</param>
  43. /// <param name="disposable4">The four disposable resoruce to add to the group.</param>
  44. /// <returns>Group of disposable resources that are disposed together.</returns>
  45. public static ICancelable Create(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
  46. {
  47. if (disposable1 == null) throw new ArgumentNullException("disposable1");
  48. if (disposable2 == null) throw new ArgumentNullException("disposable2");
  49. if (disposable3 == null) throw new ArgumentNullException("disposable3");
  50. if (disposable4 == null) throw new ArgumentNullException("disposable4");
  51. return new Quaternary(disposable1, disposable2, disposable3, disposable4);
  52. }
  53. /// <summary>
  54. /// Creates a new group of disposable resources that are disposed together.
  55. /// </summary>
  56. /// <param name="disposables">Disposable resources to add to the group.</param>
  57. /// <returns>Group of disposable resources that are disposed together.</returns>
  58. public static ICancelable Create(params IDisposable[] disposables)
  59. {
  60. if (disposables == null) throw new ArgumentNullException("disposables");
  61. return new NAry(disposables);
  62. }
  63. /// <summary>
  64. /// Creates a new group of disposable resources that are disposed together. Array is not copied, it's unsafe but optimized.
  65. /// </summary>
  66. /// <param name="disposables">Disposable resources to add to the group.</param>
  67. /// <returns>Group of disposable resources that are disposed together.</returns>
  68. public static ICancelable CreateUnsafe(IDisposable[] disposables)
  69. {
  70. return new NAryUnsafe(disposables);
  71. }
  72. /// <summary>
  73. /// Creates a new group of disposable resources that are disposed together.
  74. /// </summary>
  75. /// <param name="disposables">Disposable resources to add to the group.</param>
  76. /// <returns>Group of disposable resources that are disposed together.</returns>
  77. public static ICancelable Create(IEnumerable<IDisposable> disposables)
  78. {
  79. if (disposables == null) throw new ArgumentNullException("disposables");
  80. return new NAry(disposables);
  81. }
  82. /// <summary>
  83. /// Disposes all disposables in the group.
  84. /// </summary>
  85. public abstract void Dispose();
  86. /// <summary>
  87. /// Gets a value that indicates whether the object is disposed.
  88. /// </summary>
  89. public abstract bool IsDisposed
  90. {
  91. get;
  92. }
  93. class Binary : StableCompositeDisposable
  94. {
  95. int disposedCallCount = -1;
  96. private volatile IDisposable _disposable1;
  97. private volatile IDisposable _disposable2;
  98. public Binary(IDisposable disposable1, IDisposable disposable2)
  99. {
  100. _disposable1 = disposable1;
  101. _disposable2 = disposable2;
  102. }
  103. public override bool IsDisposed
  104. {
  105. get
  106. {
  107. return disposedCallCount != -1;
  108. }
  109. }
  110. public override void Dispose()
  111. {
  112. if (Interlocked.Increment(ref disposedCallCount) == 0)
  113. {
  114. _disposable1.Dispose();
  115. _disposable2.Dispose();
  116. }
  117. }
  118. }
  119. class Trinary : StableCompositeDisposable
  120. {
  121. int disposedCallCount = -1;
  122. private volatile IDisposable _disposable1;
  123. private volatile IDisposable _disposable2;
  124. private volatile IDisposable _disposable3;
  125. public Trinary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3)
  126. {
  127. _disposable1 = disposable1;
  128. _disposable2 = disposable2;
  129. _disposable3 = disposable3;
  130. }
  131. public override bool IsDisposed
  132. {
  133. get
  134. {
  135. return disposedCallCount != -1;
  136. }
  137. }
  138. public override void Dispose()
  139. {
  140. if (Interlocked.Increment(ref disposedCallCount) == 0)
  141. {
  142. _disposable1.Dispose();
  143. _disposable2.Dispose();
  144. _disposable3.Dispose();
  145. }
  146. }
  147. }
  148. class Quaternary : StableCompositeDisposable
  149. {
  150. int disposedCallCount = -1;
  151. private volatile IDisposable _disposable1;
  152. private volatile IDisposable _disposable2;
  153. private volatile IDisposable _disposable3;
  154. private volatile IDisposable _disposable4;
  155. public Quaternary(IDisposable disposable1, IDisposable disposable2, IDisposable disposable3, IDisposable disposable4)
  156. {
  157. _disposable1 = disposable1;
  158. _disposable2 = disposable2;
  159. _disposable3 = disposable3;
  160. _disposable4 = disposable4;
  161. }
  162. public override bool IsDisposed
  163. {
  164. get
  165. {
  166. return disposedCallCount != -1;
  167. }
  168. }
  169. public override void Dispose()
  170. {
  171. if (Interlocked.Increment(ref disposedCallCount) == 0)
  172. {
  173. _disposable1.Dispose();
  174. _disposable2.Dispose();
  175. _disposable3.Dispose();
  176. _disposable4.Dispose();
  177. }
  178. }
  179. }
  180. class NAry : StableCompositeDisposable
  181. {
  182. int disposedCallCount = -1;
  183. private volatile List<IDisposable> _disposables;
  184. public NAry(IDisposable[] disposables)
  185. : this((IEnumerable<IDisposable>)disposables)
  186. {
  187. }
  188. public NAry(IEnumerable<IDisposable> disposables)
  189. {
  190. _disposables = new List<IDisposable>(disposables);
  191. //
  192. // Doing this on the list to avoid duplicate enumeration of disposables.
  193. //
  194. if (_disposables.Contains(null)) throw new ArgumentException("Disposables can't contains null", "disposables");
  195. }
  196. public override bool IsDisposed
  197. {
  198. get
  199. {
  200. return disposedCallCount != -1;
  201. }
  202. }
  203. public override void Dispose()
  204. {
  205. if (Interlocked.Increment(ref disposedCallCount) == 0)
  206. {
  207. foreach (var d in _disposables)
  208. {
  209. d.Dispose();
  210. }
  211. }
  212. }
  213. }
  214. class NAryUnsafe : StableCompositeDisposable
  215. {
  216. int disposedCallCount = -1;
  217. private volatile IDisposable[] _disposables;
  218. public NAryUnsafe(IDisposable[] disposables)
  219. {
  220. _disposables = disposables;
  221. }
  222. public override bool IsDisposed
  223. {
  224. get
  225. {
  226. return disposedCallCount != -1;
  227. }
  228. }
  229. public override void Dispose()
  230. {
  231. if (Interlocked.Increment(ref disposedCallCount) == 0)
  232. {
  233. var len = _disposables.Length;
  234. for (int i = 0; i < len; i++)
  235. {
  236. _disposables[i].Dispose();
  237. }
  238. }
  239. }
  240. }
  241. }
  242. }