// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT License. // See the LICENSE file in the project root for more information. namespace System.Reactive.Threading { /// /// Returned by , enabling the caller to release the lock. /// public struct AsyncGateReleaser : IDisposable { // Holds either an IAsyncGate or an IDisposable. // In the case where this is an IAsyncGate, it's important that we try to avoid // calling Release more than once, because this releaser is associated with just one // call to LockAsync. IDisposable implementations are expected to be idempotent, // so we need to remember when we've already made our one call to Release. (This // can't be perfect because this is a struct, so callers might end up copying // this value and then disposing each copy. But for normal using usage that won't // be a problem, and this provides a reasonable best-effort approach. It's why // this can't be a readonly struct though.) private object _parentOrDisposable; /// /// Creates an that calls /// on its parent when disposed. /// /// public AsyncGateReleaser(IAsyncGate parent) => _parentOrDisposable = parent; /// /// Creates an that calls another disposable when disposed. /// /// /// The implementation to which to defer. /// /// /// This can be convenient for custom implementations in that wrap /// some underlying lock implementation that returns an as the means /// by which the lock is released. /// public AsyncGateReleaser(IDisposable disposable) => _parentOrDisposable = disposable; public void Dispose() { switch (_parentOrDisposable) { case IDisposable d: d.Dispose(); break; case IAsyncGate g: g.Release(); break; } _parentOrDisposable = null; } } }