Even ones in the CLR itself…
It’s well know that throwing exceptions in constructors is a bit dodgy (mainly because of possible memory leaks), but things recently got a bit weird.
It worked fine on my machine, however on my colleague’s machine Visual Studio’s unhandled exception dialog kept popping up. After he hit the continue button everything seemed to work OK, but it was still unnerving.
To cut a long story short I’d written something a bit like this[1]…
private async static Task<TcpClient> GetConnectedClient() { try { return await Task.Run<TcpClient>(() => { return new TcpClient("127.0.0.1", 80); }); } catch(SocketException ex) { Console.WriteLine(ex.ToString()); return null; } }
That particular overload of the TcpClient
constructor tries to open a connection and throws a SocketException
if it fails. The exception should be marshalled through the await
to the catch
, but it was all going a bit strange.
So I changed it to something a bit like this[1] and it all started to behave properly.
private async static Task<TcpClient> GetConnectedClient() { try { var client = new TcpClient(); await client.ConnectAsync(); return client; } catch(SocketException ex) { Console.WriteLine(ex.ToString()); return null; } }
Underneath the bonnet (or hood, if you’re not British) ConnectAsync
starts a Task
to manage the older BeginConnect
asynchronous mechanism. Nevertheless, exceptions throw in this scenario are marshalled properly with no weirdness.
Now ultimately both versions of the code seem to work correctly, but what is clear is that there is something different about the exception handling in constructors. So I’d recommend avoiding not just avoiding throwing exceptions in your own constructors but if you can, avoid using constructor that throws an exception.
[1]In order to make the point clear I’ve simplified these examples to the point where, as code, they’re not terribly useful in their own right. I certainly wouldn’t recommend using these as any kind of template.