C# – Should a Connect() Method return false on failure or throw exception

cexceptions

I found this question
Return magic value, throw exception or return false on failure?, however it is kind of broad. I would like a more specific answer.

Say I have a method called Connect() which connects to a remote device over an Ethernet socket. If the socket fails it throws SocketException.

So the way I see it I have 2 valid options.

Option 1: Capture exception and return true.

public void CallConnect()
{
    while(!Connect())
    {
        //** Log error 
    }

    //** do what ever
}


public bool Connect()
{
    try
    {
        _socket.Connect()
        return true;
    }
    catch(SocketException)
    {
        return false;
    }
    catch(<SomeOtherException1>)
    {
        return false;
    }
    catch(<SomeOtherException2>)
    {
        return false;
    }   
}

Option 2: Throw Generic Exception

public void Connect()
{
    try
    {
        _socket.Connect()
    }
    catch(SocketException ex)
    {
        throw new ConnectionException("Blah blah I failed 1", ex); 
    }
    catch(<SomeOtherException1>)
    {
        throw new ConnectionException("Blah blah I failed 2", ex);
    }
    catch(<SomeOtherException2>)
    {
        throw new ConnectionException("Blah blah I failed 3", ex);
    }   
}

public void CallConnect()
{
    bool connected == false;
    while(!connected)
    {
        try
        {
            Connect();
            connected = true;
        }
        catch(ConnectionException)
        {
            //** Log error 
        }

    }
}

My understanding if a failure is a normal or expected behavior, that no exception should be thrown, but if failure should never happen then yes an exception should be thrown.

Failing to connect could be considered expected behavior if for enable someone unplugs the Ethernet cable, or someone turns off the device it needs to communicate with, but it could also be consider exceptional behavior too.

Now if I were to ask how should handle it if send fails after I have successfully connected, I think that answer is obviously throw an exception.

Best Answer

The convention with .NET is to throw an exception, and if you want a method that returns a boolean create another method called TryFoo.

So, void Connect() would throw an exception for any sort of failure.

And bool TryConnect() would return false for any reason that Connect would throw an exception.

Examples of this convention are the various parse methods, like int int.Parse(string) which has another method called bool int.TryParse(string, out int).

The int.Parse(string) method throws an exception if it cannot parse the string. The int.TryParse(string, out int) method will return false if it cannot parse the string.

The only difference between this example in the .NET framework, and your situation is the out argument, which you don't need in your case.

This allows you two use cases:

foo.Connect();
foo.OperationThatRequiresAConnection();

The example above doesn't attempt to do any error handling. By throwing an exception you can guarantee that the next statement following a call to Connect will have an open connection. The code example above can't handle the case when a connection fails, and relies on higher level error handling in the application.

Contrast that with:

if (foo.TryConnect())
{
    foo.OperationThatRequiresAConnection();
}
else
{
    MessageBox.Show("Your username or password was incorrect. Try again.");
}

In this fictional scenario, the code can recover from a failed connection by asking the user to reenter information and try the operation again.

Library classes with no access to source code

If you are dealing with a class library that has a Connect() method, and you don't have access to the source code to add a TryConnect method --- C# extension methods to the rescue!

public static bool TryConnect(this LibraryClass connector)
{
    try
    {
        connector.Connect();

        return true;
    }
    catch (Exception)
    {
        return false;
    }
}

Then you can add your own custom application specific logging, if you wanted.

Related Topic