声明一个方法总是抛出一个异常?

时间:2010-10-08 17:38:18

标签: c# .net exception exception-handling checked-exceptions

我有一个类似...的方法。

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

这会产生编译器错误,“并非所有代码路径都返回值”。但在我的情况下,ThrowSpecificFault()将始终抛出(相应的)异常。所以我被迫在最后设置一个返回值,但这很难看。

这种模式的目的首先是因为“process()”是对外部Web服务的调用,但需要转换各种不同的异常以匹配客户端的预期接口(我认为是〜外观模式)。

任何更干净的方法吗?

12 个答案:

答案 0 :(得分:54)

我建议您将ThrowSpecificFault(ex)转换为throw SpecificFault(ex); SpecificFault方法将返回要抛出的异常对象而不是自己抛出它。更干净。

这是Microsoft's guidelines推荐的模式(查找文本“使用异常构建器方法”)。

答案 1 :(得分:9)

现在返回类型可以是类型,或“void”意味着“无返回类型”。理论上我们可以添加第二个特殊的返回类型“never”,它具有你想要的语义。包含对“never”返回方法的调用的表达式语句的结束点将被视为无法访问,因此在C#中的每个上下文中都是合法的,其中“goto”,“throw”或“return”是合法的。

现在十年后,这种情况不太可能被添加到类型系统中。下次从头开始设计类型系统时,请记住包含“从不”类型。

答案 2 :(得分:8)

这里的问题是,如果你进入catch中的f()块,你的函数永远不会返回一个值。这将导致错误,因为您将函数声明为int,这意味着您告诉编译器您的方法将返回一个整数。

以下代码将执行您要查找的内容并始终返回整数。

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

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

将return语句放在函数的末尾,你会没事的。

无论您的应用程序通过什么执行路径,确保您的方法始终返回值始终是一个好主意。

答案 3 :(得分:4)

你可以这样做:

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

答案 4 :(得分:3)

没有

想象一下,如果ThrowSpecificFault是在单独的DLL中定义的。 如果您修改DLL以不抛出异常,那么运行您的程序而不重新编译它会发生什么?

答案 5 :(得分:2)

您有三种选择:

始终返回i但预先声明:

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

从方法中返回异常并抛出:

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

或者创建一个自定义的Exception类并抛出:

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

答案 6 :(得分:1)

怎么样:

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

答案 7 :(得分:0)

不要指望ThrowSpecificFault()抛出异常。让它返回异常,然后把它扔到这里。

它实际上也更有意义。您不对“正常”流使用异常,因此如果每次都抛出异常,则异常成为规则。在函数中创建特定的异常,并将其抛在此处,因为这是流程的一个例外..

答案 8 :(得分:0)

我想你可以让ThrowSpecificFault返回一个Object,然后你可以

return ThrowSpecificFault(ex)

否则,您可以将ThrowSpecificFault重写为Exception子类型的构造函数,或者您可以将ThrowSpecificFault设置为创建异常但不抛出它的工厂。

答案 9 :(得分:0)

在你的情况下,但那是你的知识而不是编译器。现在可以说这种方法肯定会引发一些令人讨厌的异常。

试试这个

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

您也可以使用投掷关键字

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

但是那个方法应该返回一些异常而不是抛出异常。

答案 10 :(得分:0)

使用Unity.Interception清理代码。通过拦截处理,您的代码可能如下所示:

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


您在下一步中需要做的就是定义一个拦截处理程序,您可以自定义异常处理。使用此处理程序,您可以处理应用程序中引发的所有异常。好处是您不再需要使用try-catch块标记所有代码。

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

将类注册到处理程序可以通过配置文件或以编程方式完成。代码相当简单。注册后,使用Unity实例化对象,如下所示:

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

有关Unity.Interception的更多信息:

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

答案 11 :(得分:0)

从.Net Standard 2.1和.Net Core 3.0开始,您可以使用[DoesNotReturn] attribute。 那是斯蒂芬·图布(Stephen Toub)的Proposal: [DoesNotReturn]

很可惜,但是如果没有不幸的 internal ,可以将其与[StackTraceHidden]结合使用。在Consider exposing System.Diagnostics.StackTraceHiddenAttribute publicly的帮助下,情况可能会改变。