noctonura
noctonura

Reputation: 13123

Declare a method that always throws an exception?

I have a method like:

int f() {
  try {
    int i = process();
    return i;
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
}

This produces a compiler error, "not all code paths return a value". But in my case ThrowSpecificFault() will always throw (the appropriate) exception. So I am forced to a put a return value at the end but this is ugly.

The purpose of this pattern in the first place is because "process()" is a call to an external web service but need to translate a variety of different exceptions to match a client's expected interface (~facade pattern I suppose).

Any cleaner way to do this?

Upvotes: 47

Views: 17499

Answers (13)

MuiBienCarlota
MuiBienCarlota

Reputation: 2425

Since .Net Standard 2.1 and .Net Core 3.0, you can use [DoesNotReturn] attribute. It was a Stephen Toub's Proposal: [DoesNotReturn].

It's a pity but without an unfortunate internal, this could have been combined with [StackTraceHidden]. This could change with the help of Consider exposing System.Diagnostics.StackTraceHiddenAttribute publicly.

EDITED: [StackTraceHidden] is now part of .Net 6.0 thanks to Stephen Toub.

Upvotes: 7

CesarGon
CesarGon

Reputation: 15345

I suggest that you convert ThrowSpecificFault(ex) to throw SpecificFault(ex); the SpecificFault method would return the exception object to be thrown rather than throwing it itself. Much cleaner.

This is the pattern recommended by Microsoft's guidelines.

Upvotes: 88

Smarty
Smarty

Reputation: 41

@MuiBienCarlota was the right one for me since I was doing some logging.

Something like this

[DoesNotReturn]
protected void LogAndThrow(Exception ex)
{
    _log.LogError(ex, ex.Message);
    throw ex;
}

Upvotes: 4

Andrew Bezzub
Andrew Bezzub

Reputation: 16032

You can do like this:

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}

Upvotes: 6

Eric Lippert
Eric Lippert

Reputation: 660563

Right now a return type can be a type, or "void" meaning "no return type". We could in theory add a second special return type "never", which has the semantics you want. The end point of an expression statement consisting of a call to a "never" returning method would be considered unreachable, and so it would be legal in every context in C# in which a "goto", "throw" or "return" is legal.

It is highly unlikely that this will be added to the type system now, ten years in. Next time you design a type system from scratch, remember to include a "never" type.

Upvotes: 12

code4life
code4life

Reputation: 15794

Use Unity.Interception to clean up the code. With interception handling, your code could look like this:

int f() 
{
    // no need to try-catch any more, here or anywhere else...
    int i = process();
    return i;
}


All you need to do in the next step is to define an interception handler, which you can custom tailor for exception handling. Using this handler, you can handle all exceptions thrown in your app. The upside is that you no longer have to mark up all your code with try-catch blocks.

public class MyCallHandler : ICallHandler, IDisposable
{
    public IMethodReturn Invoke(IMethodInvocation input, 
        GetNextHandlerDelegate getNext)
    {
        // call the method
        var methodReturn = getNext().Invoke(input, getNext);

        // check if an exception was raised.
        if (methodReturn.Exception != null)
        {
            // take the original exception and raise a new (correct) one...
            CreateSpecificFault(methodReturn.Exception);

            // set the original exception to null to avoid throwing yet another
            // exception
            methodReturn.Exception = null;
        }

        // complete the invoke...
        return methodReturn;
    }
}

Registering a class to the handler can be done via a configuration file, or programmatically. The code is fairly straightforward. After registration, you instantiate your objects using Unity, like this:

var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();

More on Unity.Interception:

http://msdn.microsoft.com/en-us/library/ff646991.aspx

Upvotes: 0

rein
rein

Reputation: 33465

You have three options:

Always return i but pre-declare it:

int f() {
    int i = 0; // or some other meaningful default
    try {
        i = process();
    } catch(Exception ex) {
        ThrowSpecificFault(ex);
    }
    return i;
}

Return the exception from the method and throw that:

int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw GenerateSpecificFaultException(ex);
    }
}

Or create a custom Exception class and throw that:

int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}

Upvotes: 3

Robert Greiner
Robert Greiner

Reputation: 29772

The problem here, is that if you go into the catch block in f() your function will never return a value. This will result in an error because you declared your function as int which means you told the compiler that your method will return an integer.

The following code will do what you are looking for and always return an integer.

int f() {
  int i = 0;
  try {
    i = process();

  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return i;
}

put the return statement at the end of your function and you will be fine.

It's always a good idea to ensure your method will always return a value no matter what execution path your application goes through.

Upvotes: 8

In you case but that is Your knowledge not the compiler. There is now way to say that this method for sure will throw some nasty exception.

Try this

int f() {
  try {
    return process();
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return -1;
}

You can also use the throw key word

int f() {
  try {
    return process();
  } catch(Exception ex) {
    throw ThrowSpecificFault(ex);
  }
}

But then that method should return some exception instead of throwing it.

Upvotes: 0

Andrew Shelansky
Andrew Shelansky

Reputation: 5062

I suppose you could make ThrowSpecificFault return an Object, and then you could

return ThrowSpecificFault(ex)

Otherwise, you could rewrite ThrowSpecificFault as a constructor for an Exception subtype, or you could just make ThrowSpecificFault into a factory that creates the exception but doesn't throw it.

Upvotes: 0

Dave Van den Eynde
Dave Van den Eynde

Reputation: 17445

Yes.

Don't expect ThrowSpecificFault() to throw the exception. Have it return the exception, then throw it here.

It actually makes more sense too. You don't use exceptions for the 'normal' flow, so if you throw an exception every time, the exception becomes the rule. Create the specific exception in the function, and throw it here because it is an exception to the flow here..

Upvotes: 0

Tony Abrams
Tony Abrams

Reputation: 4673

How about:

int f() {
 int i = -1;
 try {
   i = process();       
 } catch(Exception ex) {
   ThrowSpecificFault(ex);
 }
 return i;
}

Upvotes: 1

SLaks
SLaks

Reputation: 888283

No.

Imagine if ThrowSpecificFault were defined in a separate DLL. If you modify the DLL to not throw an exception, then run your program without recompiling it, what would happen?

Upvotes: 4

Related Questions