CancellationToken.IsCancelRequested
algılandığında, kitaplıklarımın OperationCancelledException
'dan başka bir şeye attığından yöntemlerden çıkmasını sağlamak kötü bir uygulamadır mı? ÖrneğinCancellationToken ayarlandığında keyfi bir istisna atmak kötü bir uygulama mı?
:
async Task<TcpClient> ConnectAsync(string host, int port, CancellationToken ct)
{
var client = new TcpClient();
try
{
using (ct.Register(client.Close, true))
{
await client.ConnectAsync(host, port);
}
// Pick up strugglers here because ct.Register() may have hosed our client
ct.ThrowIfCancellationRequested();
}
catch (Exception)
{
client.Close();
throw;
}
return client;
}
iptal edildikten sonra, bu işlem ile ilgili olarak ObjectDisposedException
veya NullReferenceException
atma olasılığı vardır. (TcpClient.ConnectAsync()
atabilir Çünkü ya bir eşzamanlı çağrıldığında TcpClient.Close()
.)
Şimdi, şöyle çözeriz diye:
async Task<TcpClient> ConnectAsync(string host, int port, CancellationToken ct)
{
var client = new TcpClient();
try
{
using (ct.Register(client.Close, true))
{
try
{
await client.ConnectAsync(host, port);
}
catch (Exception)
{
// These exceptions are likely because we closed the
// connection with ct.Register(). Convert them to
// OperationCancelledException if that's the case
ct.ThrowIfCancellationRequested();
throw;
}
}
// Pick up strugglers here because ct.Register() may have hosed our client
ct.ThrowIfCancellationRequested();
}
catch (Exception)
{
client.Close();
throw;
}
return client;
}
Ve aynı şekilde uygulanabilir çağrı hiyerarşisinin her katmanında:
async Task<TcpClient> ConnectSslStreamAsync(string host, int port, CancellationToken ct)
{
var client = await ConnectAsync(host, port, ct);
try
{
ct.ThrowIfCancellationRequested();
var sslStream = new SslStream(client.getStream());
using (ct.Register(sslStream.Close))
{
try
{
await sslStream.AuthenticateAsClientAsync(...);
}
catch (Exception)
{
// These exceptions are likely because we closed the
// stream with ct.Register(). Convert them to
// OperationCancelledException if that's the case
ct.ThrowIfCancellationRequested();
throw;
}
}
// Pick up strugglers here because ct.Register() may have hosed our stream
ct.ThrowIfCancellationRequested();
}
catch (Exception)
{
client.Close();
throw;
}
return client;
}
Ancak bu, gerçekte tüm gereken, dış katmanda bir kez kontrol edildiğinde, bu ekstra kodu ekler. (İptal kaynağında.)
Bu keyfi istisnaların uçmasına izin vermek kötü bir uygulama mı? Yoksa onları en çok arayan kişiyi görmezden mi geliyorlar?
Microsoft, bir istisna atar bir yöntem açıkça eklediğinde, hayır, "kötü uygulama" akla ilk gelen şey değil. Sadece atılmadığını iddia etmek kötü bir uygulamadır. –
"ConnectAsync" in sonuna "ct.ThrowIfCancellationRequested()" koyamıyorum bile. Bu görüşmeden sonra ancak ConnectAsync'in geri dönmesinden önce jeton iptal edilirse ne olur? Kitaplık istemcisinin çeşitli yarış istisnalarıyla uğraşmasına izin vermeyi tercih ediyorum ve yalnızca olası bir yan etkiyi belgeleyecektim. – Noseratio
@Noseratio Bu 'ct.ThrowIfCancellationRequested()' var, çünkü o olmadan, '(ct.Register (...)) '' 'ConnectAsync()'' in devam ettiği açık bağlantıyı kapatabildiği ince bir yarış var. başarıya. Örneğimizde bir fark yaratamayabilir (ve arayıcı, bağlantıyı her halükarda tasfiye edecektir), fakat bu yapının, yöntemlerin uygulandığı durumlarda bütünlüğü (atomisite) korumak için muhtemelen bir kural olarak saklı tutulmaya değerdir. durumları değiştir. – antak