//****************************************************************************************************** // CompatibleCancellationToken.cs - Gbtc // // Copyright © 2016, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the MIT License (MIT), the "License"; you may not use this // file except in compliance with the License. You may obtain a copy of the License at: // // http://opensource.org/licenses/MIT // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 09/13/2016 - Ritchie Carroll // Generated original version of source code. // //****************************************************************************************************** using System; using System.Threading; namespace GSF.Threading { /// /// Represents a compatible implementation of the interface /// that interoperates with the and can be /// used to cancel an asynchronous operation. /// public class CompatibleCancellationToken : ICancellationToken { #region [ Members ] // Fields private readonly CancellationTokenSource m_source; private readonly System.Threading.CancellationToken m_token; private readonly bool m_sourceIsLocal; #endregion #region [ Constructors ] /// /// Creates a based on an existing system cancellation token source. /// /// Existing system cancellation token source. public CompatibleCancellationToken(CancellationTokenSource source) { m_source = source; m_token = source.Token; // Source is not owned, skip finalize GC.SuppressFinalize(this); } /// /// Creates a based on an existing system cancellation token. /// /// Existing system token. /// /// A created from an existing system cancellation token /// cannot be cancelled since the source for the provided token will not be available. /// public CompatibleCancellationToken(System.Threading.CancellationToken token) { // Although you could reflect and get cancellation token source, this could be dangerous on // multiple levels. Code in control of a cancellation token source may not be designed to // expect cancellation outside of its knowledge, as a result when creating a compatible // cancellation token from an existing system cancellation token, any calls to "Cancel" for // the compatible cancellation token will simply throw an exception. m_token = token; // There is no source, skip finalize GC.SuppressFinalize(this); } /// /// Creates a based on an existing GSF cancellation token. /// /// Existing GSF token. public CompatibleCancellationToken(CancellationToken token) { m_source = new CancellationTokenSource(); m_token = m_source.Token; m_sourceIsLocal = true; token.Cancelled += (sender, e) => m_source?.Cancel(); } /// /// Handle disposing of locally allocated resources, if any. /// ~CompatibleCancellationToken() { if (m_sourceIsLocal) m_source?.Dispose(); } #endregion #region [ Properties ] /// /// Gets a value that indicates whether the operation has been cancelled. /// public virtual bool IsCancelled => m_token.IsCancellationRequested; #endregion #region [ Methods ] /// /// Cancels the operation. /// /// true if the operation was cancelled; otherwise false. /// /// The token can only be cancelled if a was provided. /// /// not available, token cannot be cancelled. public virtual bool Cancel() { if ((object)m_source == null) throw new InvalidOperationException("Token cannot be cancelled."); if (m_token.IsCancellationRequested) return false; m_source.Cancel(); return true; } /// /// Gets a associated with this . /// /// A associated with this . /// /// This function will return null when the was created /// from an existing system cancellation token and not its source or a GSF cancellation token. /// public CancellationTokenSource GetTokenSource() { return m_source; } /// /// Gets a associated with this . /// /// A associated with this . public System.Threading.CancellationToken GetToken() { // Get a new token if source is available, otherwise return existing token return m_source?.Token ?? m_token; } #endregion #region [ Operators ] /// /// Implicitly converts existing system cancellation token to a . /// /// Existing system cancellation token that is converted to a . /// A based on an existing system cancellation token. public static implicit operator CompatibleCancellationToken(System.Threading.CancellationToken token) { return new CompatibleCancellationToken(token); } /// /// Implicitly converts existing system cancellation token source to a . /// /// Existing system cancellation token source that is converted to a . /// A based on an existing system cancellation token source. public static implicit operator CompatibleCancellationToken(CancellationTokenSource source) { return new CompatibleCancellationToken(source); } /// /// Implicitly converts a to an associated . /// /// Existing GSF cancellation token that is converted to an associated . /// A based on an existing GSF cancellation token. public static implicit operator System.Threading.CancellationToken(CompatibleCancellationToken token) { return token.GetToken(); } /// /// Implicitly converts a to an associated . /// /// Existing GSF cancellation token that is converted to an associated . /// A based on an existing GSF cancellation token. public static implicit operator CancellationTokenSource(CompatibleCancellationToken token) { return token.GetTokenSource(); } #endregion } }