Is it bad practice for my libraries to exit methods throwing something other than OperationCancelledException when a CancellationToken.IsCancelRequested detected?
For instance:
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); }
When invalidated, it has the ability to throw an ObjectDisposedException or NullReferenceException depending on the time. (Because TcpClient.ConnectAsync() can throw one when TcpClient.Close() is called at the same time.)
Now I could fix it like this:
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) {
And also at each level of the call hierarchy, where applicable:
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) {
But this adds this extra code, when in fact all that is required is a single check on the outermost layer. (In the source of the cancellation.)
Does bad practice allow these arbitrary exceptions to fly? Or ignore them at the most external caller?
antak source share