declare a method always throws an exception?

女生的网名这么多〃 提交于 2019-12-13 12:24:35

问题


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?


回答1:


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 (find the text "Use exception builder methods").




回答2:


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.




回答3:


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.




回答4:


You can do like this:

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



回答5:


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?




回答6:


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);
    }
}



回答7:


How about:

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



回答8:


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




回答9:


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.




回答10:


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.




回答11:


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




回答12:


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.



来源:https://stackoverflow.com/questions/3892938/declare-a-method-always-throws-an-exception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!