Declare a method that always throws an exception?
Asked Answered
C

13

44

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?

Chromophore answered 8/10, 2010 at 17:38 Comment(1)
C
85

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.

Colugo answered 8/10, 2010 at 17:41 Comment(5)
+1, this is the pattern recommended in Microsoft's guidelines.Sheared
I do: msdn.microsoft.com/en-us/library/seyhszts.aspx; find the text "Use exception builder methods".Colugo
This is the one true solution. Everything else is just fluff, in my opinion.Haemato
I've the same problem, and this option is not valid. because in my case "ThrowSpecificFault" is an object that's already defined before and have some data. so I want that object to throw the exception with that data he have.Rhizotomy
Unfortunately, this is a simplistic answer that usually works (and works for the simplistic example), but utterly fails if you were trying to do some logging every time and were trying to be good and wrap it in a function for reusability.Sesquioxide
W
12

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.

Weighbridge answered 8/10, 2010 at 19:37 Comment(0)
R
8

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.

Rouen answered 8/10, 2010 at 17:40 Comment(1)
While this will work, this code is not really ideal because it might trick the reader into thinking that i will be returned even if process() throws an exception. It would be better to use a throw statement in the catch block.Fairlie
F
6

You can do like this:

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
Familiarize answered 8/10, 2010 at 17:42 Comment(0)
B
4

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?

Bakery answered 8/10, 2010 at 17:40 Comment(5)
Imagine if method Foo were defined in a separate DLL. If you modify Foo to return a long instead of an int, then run your program which calls Foo without recompiling it, what would happen? Nothing good. It is never correct to change the signature of a method in an external library and then keep using it without recompiling. That's why we have version stamps, etc, on assemblies.Weighbridge
@Eric - I believe that SLaks's hypothetical situation doesn't require changing the signature, so it's not as obviously a breaking change.Subroutine
@kvb: The proposed feature, as I understand it, is to capture the fact that a method never returns in its signature.Weighbridge
@Eric: While that feature would solve the OPs problem, I did not get the impression that the OP was looking for that feature specifically, but instead not realizing why it was an issue. I think SLak's point is that since the signature does not indicate that the method never returns, the OP's request is not possible. If the "never" return type existed, the OP would change the signature of ThrowSpecificFault and be done.Lott
Could an attribute not be added to the framework that marks the method as "always throws"? If the method ever changes such that it doesn't always throw, it would generate a compiler error.Fetter
B
4

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.

Bally answered 4/12, 2019 at 13:25 Comment(0)
D
3

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);
    }
}
Devilkin answered 8/10, 2010 at 17:41 Comment(0)
R
3

@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;
}
Reprobative answered 4/10, 2021 at 7:58 Comment(0)
H
1

How about:

int f() {
 int i = -1;
 try {
   i = process();       
 } catch(Exception ex) {
   ThrowSpecificFault(ex);
 }
 return i;
}
Heckelphone answered 8/10, 2010 at 17:41 Comment(1)
I'm leaving this as an answer, but Robert Greiner beat me to it.Heckelphone
H
0

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..

Haemato answered 8/10, 2010 at 17:41 Comment(0)
F
0

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.

Flo answered 8/10, 2010 at 17:41 Comment(0)
E
0

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.

Ecumenicism answered 8/10, 2010 at 17:44 Comment(0)
S
0

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

Sparse answered 8/10, 2010 at 17:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.