2

I have the common scenario of needing to write a pair of methods:

  • One that gets a result and throws an exception if it fails, and
  • a Try-variant of the same method that attempts to get the result as an out param, and returns a bool that indicates success status.

Here are two examples that illustrate the two approaches that I am considering. Which of these approaches provides the best performance? Also, is one approach likely to be easier to maintain than the other? I am also open to suggestions for other ways to implement this pair of methods.

Method 1: Foo() as master

public string GetAnswer(string question) {

    string answer = null;

    if(!this.TryGetAnswer(question, out answer)) {
        throw new AnswerNotFoundException();
    }

    return answer;
}

public bool TryGetAnswer(string question, out string answer) {

    answer = null;

    //business logic

    return answer != null;
}

Method 2: TryFoo() as master

public string GetAnswer(string question) {

    //business logic

    if(!answerFound) {
        throw new AnswerNotFoundException();
    }
    return answer;
}

public bool TryGetAnswer(string question, out string answer) {

    try {
        answer = this.GetAnswer(question);
        return true;
    } catch (AnswerNotFoundException e) {
        answer = null;
        return false;
    }
}
DavidRR
  • 18,291
  • 25
  • 109
  • 191
Robin B.
  • 71
  • 6
  • 3
    Do you have a specific question here? Otherwise, this question is too broad and opinion based. – rory.ap Nov 08 '16 at 13:24
  • 3
    go with the first one. Exceptions should be exceptional - you shouldn't have to use an exception to manage program flow if you can help it. Eric Lippert [has a good, short article on this](https://blogs.msdn.microsoft.com/ericlippert/2008/09/10/vexing-exceptions/) – Jonesopolis Nov 08 '16 at 13:25
  • I suspect this would be better suited for the Code Review Stack Exchange site. Though I'll certainly be interested in the replies there. My personal opinion is to lean toward the first one, as it favors not using exceptions for control flow. – David Nov 08 '16 at 13:25
  • I prefer the first one myself but this is pretty subjective. – paxdiablo Nov 08 '16 at 13:25
  • Totally subjective but I would say the first one. – Steve Nov 08 '16 at 13:25
  • 3
    Controlling program flow by exception is expensive, so the second approach is more likely to be slower than the first. – ChrisF Nov 08 '16 at 13:26
  • 1
    Ask yourself whether `AnswerNotFound` is really an exception or something that *is* expected. If it does, just returning `null` is better. – haim770 Nov 08 '16 at 13:26
  • 2
    @David actually this isn't suited for [codereview.se]. Code that's stripped of details is not allowed there. For more information, you might want to read [A Guide to Code Review for Stack Overflow users](http://meta.codereview.stackexchange.com/questions/5777/a-guide-to-code-review-for-stack-overflow-users) – Vogel612 Nov 08 '16 at 13:27
  • 3
    You could always take a look at the reference source for inspiration. E.g. here's [`Boolean.Parse`](https://referencesource.microsoft.com/#mscorlib/system/boolean.cs,158) which is followed by `TryParse`. – Damien_The_Unbeliever Nov 08 '16 at 13:28
  • 1
    @haim770 - that may be true, but the code he's emulating (int.Parse, etc.) throws an exception if it gets invalid input. – ChrisF Nov 08 '16 at 13:28
  • @Vogel612: Good to know, thanks for the link! – David Nov 08 '16 at 13:29
  • @Robin I edited your question so that it has a better chance of not being closed as opinion-based. – DavidRR Nov 08 '16 at 14:11
  • Thank you all for the helpful inputs and @DavidRR for the edit, appreciated. I've accepted your answer, lots of good information there. I also wasn't aware of the reference source, that will prove invaluable for future questions. – Robin B. Nov 08 '16 at 15:51

1 Answers1

1

The point of the TryFoo() API pattern is to avoid the overhead of (potentially) throwing an exception that the companion Foo function does.

Your first example accomplishes this. Also note that the pattern in your first example is supported by Microsoft itself in its reference source for Boolean.TryParse and Boolean.Parse.

Finally, note that Code Analysis will raise CA1021: Avoid out parameters if you include an out parameter in a public method. The question Code analysis comes back with suggestion about not using “out” parameters discusses this warning. The top-voted answer indicates that the TryParse idiom is well-established. Therefore, making use of the TryParse approach in a public API has a good chance of being well-received. So, a reasonable (though subjective) argument can made in this case to suppress warning CA1021.


† Links suggested by Damien_The_Unbeliever

Community
  • 1
  • 1
DavidRR
  • 18,291
  • 25
  • 109
  • 191
  • thank you a lot for supplying the answer with these useful sources. I was aware of the out parameter debate as well, and would also support that it should be a valid use-case since the scenario is well-established. Avoiding exceptions for program flow is a solid and sufficient point I'd say. I wasn't exactly sure about it initially because I understood the TryX paradigm as "silently consume the error that would normally occur", but avoiding it altogether seems to be the better option. Thanks! – Robin B. Nov 08 '16 at 15:48
  • thanks for the heads-up. I am using SO for a while now (mostly passively), and tried to find a similar problem/question for 10 minutes to no avail. Are there any better ways to scan for duplicates? Maybe it was due to a wrong degree of abstraction (e.g. I could have boiled the problem down to "is documentation available for existing TryX implementations"). As for general question guidelines, I feel the question does have a clear "better" answer/resolution and can be answered based on facts, and would as such qualify for SO (but please correct me if wrong). Thanks! – Robin B. Nov 10 '16 at 08:55