Ну, из исходного кода класса CancellationToken вроде бы так. Метод ExecuteCallbackHandlers(bool throwOnFirstException)
отвечает за получение обратных вызовов и их выполнение. Содержит этот фрагмент кода:
try
{
for (int index = 0; index < callbackLists.Length; index++)
{
SparselyPopulatedArray<CancellationCallbackInfo> list = Volatile.Read<SparselyPopulatedArray<CancellationCallbackInfo>>(ref callbackLists[index]);
if (list != null)
{
SparselyPopulatedArrayFragment<CancellationCallbackInfo> currArrayFragment = list.Tail;
while (currArrayFragment != null)
{
for (int i = currArrayFragment.Length - 1; i >= 0; i--)
{
... some other code
}
}
}
}
}
Во внутреннем цикле for
он переходит фрагмент массива обратных вызовов назад от последнего к первому элементу.
Однако, как отмечает @Nick, это не гарантируется в документации. Простым решением было бы добавить обратные вызовы в один делегат - таким образом мы имеем больше контроля над порядком выполнения:
token.Register(() =>
{
Console.WriteLine("1"));
Console.WriteLine("2"));
Console.WriteLine("3"));
});