How do I know if a CancellationToken has a registered cancellation method?

I have a parent containing a CancellationTokenSource

. This object passes its own CancellationToken

to the process, which communicates sequentially with external services. Whenever a call is made to an external service, it is CancellationToken

registered with a method that will allow the process to stop waiting for a response from the external service:

myObj.CancellationTokenRegistration.Dispose();
myObj.CancellationTokenRegistration = myObj.CancellationToken.Register(() => CancelMethod(myObj));

      

Given only CancellationTokenSource

, is there a way to know that the cancellation method was registered against the token?

+3


source to share


3 answers


Without using reflection (or other types of voodoo) to look at the internal state CancellationTokenSource

, there is no way to tell if any code has added any registrations.

If you want to use reflection, you should look at this field:



private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;

      

0


source


The m_callbackInfo field appears to contain the same information.



        CancellationTokenSource cts = new CancellationTokenSource();
        Action test = CancelMethod;
        CancellationTokenRegistration = cts.Token.Register(test);
        var fieldInfo = typeof(CancellationTokenRegistration).GetField("m_callbackInfo", BindingFlags.NonPublic | BindingFlags.Instance);
        object fieldValue = fieldInfo.GetValue(CancellationTokenRegistration);
        var callbackFieldInfo = fieldValue.GetType().GetField("Callback", BindingFlags.Instance | BindingFlags.NonPublic);
        var callbackValue = callbackFieldInfo.GetValue(fieldValue);
        var stateForCallbackFieldInfo = fieldValue.GetType().GetField("StateForCallback", BindingFlags.Instance | BindingFlags.NonPublic);
        var stateForCallbackValue = stateForCallbackFieldInfo.GetValue(fieldValue);
        // stateForCallbackValue == CancelMethod; if Token.Register is called with one of the Action<object> arguments 
        // callbackValue == CancelMethod

        private void CancelMethod()
        {
            throw new System.NotImplementedException();
        }

      

0


source


Here is some example code using reflection to enumerate registered actions (works as expected in .Net 4.7.1):

public static IEnumerable<Action<object>> Registrations(this CancellationToken token)
{
        var sourceFieldInfo = typeof(CancellationToken).GetField("m_source", BindingFlags.NonPublic | BindingFlags.Instance);

        var cancellationTokenSource = (CancellationTokenSource)sourceFieldInfo.GetValue(token);

        var callbacksFieldInfo = typeof(CancellationTokenSource).GetField("m_registeredCallbacksLists", BindingFlags.NonPublic | BindingFlags.Instance);

        var callbaskLists = (Array)callbacksFieldInfo.GetValue(cancellationTokenSource);

        foreach (var sparselyPopulatedArray in callbaskLists)
        {
            if (sparselyPopulatedArray == null)
            {
                continue;
            }

            var sparselyPopulatedArrayType = sparselyPopulatedArray.GetType();

            var tailFieldInfo = sparselyPopulatedArrayType.GetProperty("Tail", BindingFlags.NonPublic | BindingFlags.Instance);

            var tail = tailFieldInfo.GetValue(sparselyPopulatedArray);

            var sparselyPopulatedArrayFragmentType = tail.GetType();

            var elementsTypeFieldInfo = sparselyPopulatedArrayFragmentType.GetField("m_elements", BindingFlags.NonPublic | BindingFlags.Instance);

            var elements = (Array)elementsTypeFieldInfo.GetValue(tail);

            foreach (var callbackInfo in elements)
            {
                if (callbackInfo == null)
                {
                    continue;
                }

                var callbackInfoType = callbackInfo.GetType();

                var callbackFieldInfo = callbackInfoType.GetField("Callback", BindingFlags.NonPublic | BindingFlags.Instance);

                var callback = (Action<object>)callbackFieldInfo.GetValue(callbackInfo);

                if (callback != null)
                {
                    yield return callback;
                }
            }
        }
    }

      

0


source







All Articles