When should I use a ThrowHelper method instead of throwing directly?
Asked Answered
L

8

20

When is it appropriate to use a ThrowHelper method instead of throwing directly?

void MyMethod() {
    ...
    //throw new ArgumentNullException("paramName");
    ThrowArgumentNullException("paramName");
    ...
}
void ThrowArgumentNullException(string paramName) {
    throw new ArgumentNullException(paramName);
}

I've read that calling a ThrowHelper method (a method with the only purpouse of throwing an exception) instead of throwing directly should yield smaller bytecode.

This, and the obvious encapsulation (another layer of indirection), may be good reasons to not throw directly, at least in some scenarios.

Anyway, IMO the drawbacks are not insubstantial too.

  • A part of the (exceptional) control flow is hidden
  • Exceptions end up having a more cryptic stacktrace
  • the compiler (2.0) will not recognize that ThrowHelper calls are exit points from a method, hence some code-around is necessary.

My limited experience is that often the overall design gets worse.

int MyMethod(int i) {
    switch (i) {
        case 1:
            return 1;
        default:
            ThrowMyException();
    }
    return 0; // Unreachable (but needed) code
 }

This may partly be a matter of personal taste. Anyway what are your personal guidelines about this issue? Do you find it is a good idea to use ThrowHelpers for all those common tasks like method param validation (ThrowArgumentNullException(paramName) and such)? Am I missing something obvious on this issue?

Btw I'm trying not to mix this issue with the validation issue, e.g. a method like:

ThrowIfNameIsNullOrEmpty(name);
Lucielucien answered 30/12, 2009 at 12:48 Comment(3)
Wow. I'd not seen this pattern before but like you my immediate reaction is very negative. The bytecode size thing must surely be a premature optimisation for the vast majority of cases.Ysabel
Microsoft used ThrowHelper when designing Stack<T>: pastebin.com/p2k4URtUCouperin
You can tell the compiler that a certain method always throws an exception: #3893438Modiste
C
19

My default approach is to throw directly from the exceptional code branch.

The DRY principle and the rule of 3 guides when I would wrap that in a method: if I find myself writing the same 'throw' code 3 or more times, I consider wrapping it in a helper method.

However, instead of a method that throws, it's much better to write a Factory Method that creates the desired Exception and then throw it from the original place:

public void DoStuff(string stuff)
{
    // Do something

    throw this.CreateException("Boo hiss!");
}

private MyException CreateException(string message)
{
    return new MyException(message);
}

This preserves the stack trace.

Chinchin answered 30/12, 2009 at 12:59 Comment(0)
V
9

This seems like a needless abstraction to me. You have a method that does one thing, named as verbosely as the thing that it does.

The argument about less bytecode is practically meaningless since the size of your code rarely matters (you wouldn't be saving more than a kilobyte per instance of your program, unless you throw that exception from a ridiculous number of places in your source code). Meanwhile your stated drawbacks are all real concerns, especially where clarity of exception handling is concerned.

Basically abstracting away minor things like this usually comes back to bite you. (Some entertaining reading on the subject: http://www.joelonsoftware.com/articles/LeakyAbstractions.html)

Vengeful answered 30/12, 2009 at 12:59 Comment(0)
M
6

There are two justifiable reasons to do this. The first is if the same exception message / info is supposed to be shared in multiple places.

The second is for performance reasons. Historically a throw in a method would prevent that method from being inlined which can drastically impact performance for small methods. You see this very often in collection types where small methods that modify the collection need to check the bounds before performing the modification.

The idea is that we want the normal case to be inlined as far up the stack as possible and to do so the throw has to stay in it's own method which is not inlined.

See these blog posts among many others for further explanation : https://devblogs.microsoft.com/dotnet/performance_improvements_in_net_7/#exceptions https://devblogs.microsoft.com/dotnet/performance-improvements-in-net-5/

Mensurable answered 9/12, 2022 at 0:29 Comment(0)
C
5

I would say that the only reasonable time to do this is in something like the BCL where the amount of usage of the class is wide spread enough that the savings may be worth it. It would have to make sense, however. In your case, I don't think you're actually saving any space. Instances of ThrowHelper in the BCL reduce size by substituting enums for strings and method calls (to get string messages). Your case simply passes the same arguments and thus doesn't achieve any savings. It costs just as much to call your method as it does to throw the exception in place.

Chipmunk answered 30/12, 2009 at 13:9 Comment(1)
Get your point. If the weight is not usage of 'throw' keyword itself but parameter passing, this kind of helper yields no performance improvement.Lucielucien
T
3

From what I've understood, the smaller bytecode is pretty much the only advantage (See this question), so I don't expect you'll see a lot of arguments for it in the answers here.

Terricolous answered 30/12, 2009 at 13:5 Comment(0)
M
1

I always try to throw my own exceptions for the mere purpose of customization. I can throw a message that is going to tell me in short order what the problem is (and possibly where it originated from). As far as performance issues go, I try to limit the number of exceptions thrown on the release versions of my software as much as possible, so I have never actually thought about it too much. I am interested to see what other say though.

That is my 2 cents. Please take it as such.

Murder answered 30/12, 2009 at 12:58 Comment(0)
W
0

One advantage not yet mentioned to using either a throw-helper or exception-factory method is the possibility of passing a delegate for such a purpose. When using a throw-helper delegate, one gains the possibility of not throwing (which would in some cases be a good thing; in other cases, a bad thing). For example:

string TryGetEntry(string key, Funct<problemCause, string> errorHandler)
{
  if (disposed)
    return errorHandler(problemCause.ObjectDisposed);
  else if (...entry_doesnt_exist...)
    return errorHandler(problemCause.ObjectNotFound);
  else
    return ...entry...;
}
string GetEntry(string key)
{
  return TryGetEntry(key, ThrowExceptionOnError);
}
bool TryGetEntry(string key, ref result)
{
  bool ok;
  string result;
  result = TryGetEntry(key, (problemCause theProblem) => {ok=false; return (string)null;});
  return ok;
}

Using this approach, one may easily use one routine with a variety of error-handling strategies. One could eliminate the need for a closure by having the TryGetEntry method accept a generic type parameter along with a 'ref' parameter of that type and a delegate that accepts such a 'ref' parameter; the example is simpler, though, just using a closure.

Wealth answered 30/1, 2012 at 18:44 Comment(1)
This is smart, but I prefer a more straightforward approach... Just not to worry abount errors in the errorhandler ... :-)Lucielucien
C
0

Although having smaller bytecode seems only save you a few kb, it definetly "does" effect performance because more code have to be fetched/loaded to run your method which also means more cpu cache wasted. If you write high perf code where every micro-optimisation matters then it matters.

But what is more important you can localize or one day may want to localize your exception messages.

Chaps answered 1/1, 2022 at 18:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.