Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

"TryParse / Parse like" pattern: what is the best way to implement it

This question is a follow-up from How to indicate that a method was unsuccessful. The xxx() Tryxxx() pattern is something that can be very useful in many libraries. I am wondering what is the best way to offer both implementations without duplicating my code.

What is best:

public int DoSomething(string a)
{
     // might throw an exception
}
public bool TrySomething(string a, out result)
{
    try
    {
        result = DoSomething(a)
        return true;
    }
    catch (Exception)
    {
        return false;
    }

or

public int DoSomething(string a)
{
     int result;
     if (TrySomething(a, out result))
     {
         return result;
     }
     else
     {
         throw Exception(); // which exception?
     }
}
public bool TrySomething(string a, out result)
{
    //...
}

I'd instinctively assume that the first example is more correct (you know exactly which exception happened), but couldn't the try/catch be too expensive? Is there a way to catch the exception in the second example?

like image 795
Luk Avatar asked Oct 08 '08 12:10

Luk


1 Answers

Making TrySomething just catch and swallow the exception is a really bad idea. Half the point of the TryXXX pattern is to avoid the performance hit of exceptions.

If you don't need much information in the exception, you could make the DoSomething method just call TrySomething and throw an exception if it fails. If you need details in the exception, you may need something more elaborate. I haven't timed where the bulk of the performance hit of exceptions is - if it's the throwing rather than the creating, you could write a private method which had a similar signature to TrySomething, but which returned an exception or null:

public int DoSomething(string input)
{
    int ret;
    Exception exception = DoSomethingImpl(input, out ret);
    if (exception != null)
    {
        // Note that you'll lose stack trace accuracy here
        throw exception;
    }
    return ret;
}

public bool TrySomething(string input, out int ret)
{
    Exception exception = DoSomethingImpl(input, out ret);
    return exception == null;
}

private Exception DoSomethingImpl(string input, out int ret)
{
    ret = 0;
    if (input != "bad")
    {
        ret = 5;
        return null;
    }
    else
    {
        return new ArgumentException("Some details");
    }
}

Time this before you commit to it though!

like image 179
Jon Skeet Avatar answered Oct 26 '22 21:10

Jon Skeet