为什么在CancellationToken中存储的CancellationToken与CancellationTokenSource提供的令牌不同?
[Test]
public static async Task SqlCommand_should_recognise_which_CT_triggered_its_cancellation()
{
var timeout = TimeSpan.FromSeconds(1);
var cts = new CancellationTokenSource(timeout);
try
{
var connection = new SqlConnection(_config.ConnectionString);
await connection.OpenAsync(cts.Token);
var sqlQuery = new SqlCommand("select 1", connection);
await Task.Delay(timeout + TimeSpan.FromSeconds(1));
await sqlQuery.ExecuteScalarAsync(cts.Token);
}
catch (OperationCanceledException cancelledEx)
{
//Shouldn't they be the same?
Assert.AreEqual(cancelledEx.CancellationToken, cts.Token);
// The below fails as well
// Assert.IsTrue(cancelledEx.CancellationToken == cts.Token);
}
}
答案 0 :(得分:2)
为什么在CancellationToken中存储的CancellationToken与CancellationTokenSource提供的令牌不同?
这是一个实现细节。我没有查看来源,但我可疑的情况是,提供给CancellationToken
的{{1}}与一些内部ExecuteScalarAsync
组合在一起,这意味着“我们失去了联系”或类似的东西。这些linked CancellationToken
s不等同于其来源CancellationToken
。
这通常是CancellationToken
的使用问题。使用链接令牌,并非总是能够确定哪个 取消令牌导致了取消。因此,建议您通过CancellationToken
检查取消令牌的自己副本:
catch (OperationCanceledException ex) when (cts.IsCancellationRequested)
在竞争情况下,您的代码可能会认为发生取消是因为超时,但实际上是由于连接断开(或发生任何内部逻辑)导致的,在大多数情况下,这都没有关系。