views:

270

answers:

11

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?

+3  A: 

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?

SLaks
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.
Eric Lippert
@Eric - I believe that SLaks's hypothetical situation doesn't require changing the signature, so it's not as obviously a breaking change.
kvb
@kvb: The proposed feature, as I understand it, is to capture the fact that a method never returns *in its signature*.
Eric Lippert
@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.
Brian
+7  A: 

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.

Robert Greiner
+1 you beat me by a minute!!
Tony Abrams
+1  A: 

How about:

int f() {
 int i = -1;
 try {
   i = process();       
 } catch(Exception ex) {
   ThrowSpecificFault(ex);
 }
 return i;
}
Tony Abrams
I'm leaving this as an answer, but Robert Greiner beat me to it.
Tony Abrams
+20  A: 

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

CesarGon
+1, this is the pattern recommended in Microsoft's guidelines.
Joe
Do you have a link?
RichAmberale
I do: http://msdn.microsoft.com/en-us/library/seyhszts.aspx; find the text "Use exception builder methods".
CesarGon
This is the one true solution. Everything else is just fluff, in my opinion.
Dave Van den Eynde
+1  A: 

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);
    }
}
rein
A: 

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

Dave Van den Eynde
A: 

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.

Andrew Shelansky
+3  A: 

You can do like this:

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
Andrew Bezzub
A: 

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.

Vash
A: 

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

code4life
+4  A: 

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.

Eric Lippert