如何知道CancellationToken是否有已注册的取消方法
本文关键字:注册 取消 方法 何知道 CancellationToken 是否 | 更新日期: 2023-09-27 17:51:19
我有一个包含CancellationTokenSource
的父对象。该对象将其CancellationToken
传递给与外部服务进行顺序通信的进程。每当调用外部服务时,CancellationToken
被注册到一个方法,该方法将允许进程停止等待外部服务响应:
myObj.CancellationTokenRegistration.Dispose();
myObj.CancellationTokenRegistration = myObj.CancellationToken.Register(() => CancelMethod(myObj));
仅给定CancellationTokenSource
,是否有一种方法可以知道针对令牌注册了取消方法?
如果不使用反射(或其他类型的巫术)来查看CancellationTokenSource
的内部状态,就没有办法知道某些代码是否添加了任何注册。
如果你想使用反射,你应该看看这个字段:
private volatile SparselyPopulatedArray<CancellationCallbackInfo>[] m_registeredCallbacksLists;
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();
}
下面是一些使用反射枚举已注册动作的粗略代码(在。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;
}
}
}
}