Add CancellationTokenRegistration.OnUnregisteredWithoutInvoke(Action)
API
#60755
Replies: 2 comments 4 replies
-
You can open an issue with api-proposal category to increase visibility. |
Beta Was this translation helpful? Give feedback.
-
@stephentoub #60843 was locked, so I thought I should post here rather than create a new issue (this is what I was trying to do after all). Trying to hook up my custom cancelation token to BCL token, I'm stuck on 2 parts.
For both of these, I had the thought to use reflection to extract the wrapped source from the token to be able to use it in a WeakReference, and its partial class Extensions
{
/// <summary>
/// Convert <paramref name="token"/> to a <see cref="CancelationToken"/>.
/// </summary>
/// <param name="token">The cancellation token to convert</param>
/// <returns>A <see cref="CancelationToken"/> that will be canceled when <paramref name="token"/> is canceled.</returns>
public static CancelationToken ToCancelationToken(this System.Threading.CancellationToken token)
{
if (!token.CanBeCanceled)
{
return default(CancelationToken);
}
if (token.IsCancellationRequested)
{
return CancelationToken.Canceled();
}
return new TokenWrapper(Internal.CancelationRef.GetOrCreate(), token).Token;
}
private sealed class TokenWrapper
{
// Is it even possible for the internal CancellationTokenSource to be finalized if we have a field here and this is resurrected?
// We can't use WeakReference because it's a value type.
internal readonly System.Threading.CancellationToken _bclToken;
private readonly Internal.CancelationRef _cancelationRef;
private readonly int _tokenId;
internal CancelationToken Token { get { return new CancelationToken(_cancelationRef, _tokenId); } }
internal TokenWrapper(Internal.CancelationRef cancelationRef, System.Threading.CancellationToken token)
{
_bclToken = token;
_cancelationRef = cancelationRef;
_tokenId = cancelationRef.TokenId;
RegisterCancelation();
}
~TokenWrapper()
{
// How can we tell if the token was disposed/finalized vs TryReset?
// CanBeCanceled obviously doesn't work.
if (!_bclToken.CanBeCanceled)
{
_cancelationRef.Dispose();
return;
}
GC.ReRegisterForFinalize(this);
_cancelationRef.ClearListeners();
RegisterCancelation();
}
private void RegisterCancelation()
{
_bclToken.Register(state =>
{
GC.SuppressFinalize(state);
var wrapper = Unsafe.As<TokenWrapper>(state);
wrapper._cancelationRef.Cancel();
}, this, false);
}
}
} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Currently, I have no way of knowing if/when my callback registered via
CancellationToken.Register(Action)
was removed from the token without it being invoked without me explicitly removing it myself viaCancellationTokenRegistration.Unregister
. Like when the source is disposed without Cancel having ever been called, or if the newTryReset
is called.This would be useful for cleaning up resources that have no definite expiration aside from the life of the registration.
Adjusting the MSDN example, I could do this:
But this won't work if the object I need to clean up is relying entirely on the lifetime of the registered action, not some other async action.
Beta Was this translation helpful? Give feedback.
All reactions