MultipleAssignmentDisposable.cs 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. // Licensed to the .NET Foundation under one or more agreements.
  2. // The .NET Foundation licenses this file to you under the Apache 2.0 License.
  3. // See the LICENSE file in the project root for more information.
  4. namespace System.Reactive.Disposables
  5. {
  6. /// <summary>
  7. /// Represents a disposable resource whose underlying disposable resource can be swapped for another disposable resource.
  8. /// </summary>
  9. public sealed class MultipleAssignmentDisposable : ICancelable
  10. {
  11. private readonly object _gate = new object();
  12. private IDisposable _current;
  13. /// <summary>
  14. /// Initializes a new instance of the <see cref="T:System.Reactive.Disposables.MultipleAssignmentDisposable"/> class with no current underlying disposable.
  15. /// </summary>
  16. public MultipleAssignmentDisposable()
  17. {
  18. }
  19. /// <summary>
  20. /// Gets a value that indicates whether the object is disposed.
  21. /// </summary>
  22. public bool IsDisposed
  23. {
  24. get
  25. {
  26. lock (_gate)
  27. {
  28. // We use a sentinel value to indicate we've been disposed. This sentinel never leaks
  29. // to the outside world (see the Disposable property getter), so no-one can ever assign
  30. // this value to us manually.
  31. return _current == BooleanDisposable.True;
  32. }
  33. }
  34. }
  35. /// <summary>
  36. /// Gets or sets the underlying disposable. After disposal, the result of getting this property is undefined.
  37. /// </summary>
  38. /// <remarks>If the MutableDisposable has already been disposed, assignment to this property causes immediate disposal of the given disposable object.</remarks>
  39. public IDisposable Disposable
  40. {
  41. get
  42. {
  43. lock (_gate)
  44. {
  45. if (_current == BooleanDisposable.True /* see IsDisposed */)
  46. return DefaultDisposable.Instance; // Don't leak the sentinel value.
  47. return _current;
  48. }
  49. }
  50. set
  51. {
  52. var shouldDispose = false;
  53. lock (_gate)
  54. {
  55. shouldDispose = (_current == BooleanDisposable.True /* see IsDisposed */);
  56. if (!shouldDispose)
  57. {
  58. _current = value;
  59. }
  60. }
  61. if (shouldDispose && value != null)
  62. value.Dispose();
  63. }
  64. }
  65. /// <summary>
  66. /// Disposes the underlying disposable as well as all future replacements.
  67. /// </summary>
  68. public void Dispose()
  69. {
  70. var old = default(IDisposable);
  71. lock (_gate)
  72. {
  73. if (_current != BooleanDisposable.True /* see IsDisposed */)
  74. {
  75. old = _current;
  76. _current = BooleanDisposable.True /* see IsDisposed */;
  77. }
  78. }
  79. if (old != null)
  80. old.Dispose();
  81. }
  82. }
  83. }