4

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.

13

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.

  • 1
    Yes, the main point is the contract, i.e. what the user expects the method to do. After returning from Connect() I expect the connection to be established (and to get an exception otherwise), after TryConnect() I know I have to check some result value. – Ralf Kleberhoff Apr 14 '18 at 14:56
1

I don't agree with @Greg Burghardt's answer because it depends on the context.

You want to follow the advice of throwing exceptions when you write library code because you very likely won't have any logging there and you want to know what went wrong.

If you however use this code and wrap in some project local helper that adds logging or some other stuff, your new Connect method might as well just return boolean.

  • 1
    Library code should throw exceptions. The thing using the library should be doing error handling as close to the library API calls as possible. As a last resort something at the application level should trap the exception and log it to a file, database, or the Windows Event Log. Your idea of using a helper class or method that returns a boolean is a good option if you don't have any control over the library code. +1 for that. – Greg Burghardt Apr 25 '18 at 11:52
  • But if you want the new method to return a boolean then why not call it TryConnect as per the conventions? – JacquesB Apr 25 '18 at 22:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.