3

我有一个包含CancellationTokenSource. 该对象将其传递CancellationToken到与外部服务顺序通信的进程中。每当调用外部服务时,CancellationToken都会将其注册到一个允许进程停止等待外部服务响应的方法:

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

仅给定CancellationTokenSource,有没有办法知道已针对令牌注册了取消方法?

4

3 回答 3

0

如果不使用反射(或其他类型的巫术)来查看内部状态,CancellationTokenSource就无法知道某些代码是否添加了任何注册。

如果您确实想使用反射,您应该查看此字段:

private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
于 2015-06-01T15:10:12.773 回答
0

m_callbackInfo 字段似乎包含相同的信息。

        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();
        }
于 2015-06-01T15:53:56.880 回答
0

这是一些使用反射来枚举已注册操作的粗略代码(与 .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;
                }
            }
        }
    }
于 2018-12-11T15:00:33.913 回答