//******************************************************************************************************
// 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
}
}