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

C# 声明一个方法总是抛出异常?,c#,.net,exception,exception-handling,checked-exceptions,C#,.net,Exception,Exception Handling,Checked Exceptions,我有一个方法像 int f() { try { int i = process(); return i; } catch(Exception ex) { ThrowSpecificFault(ex); } } 这会产生一个编译器错误,“并非所有代码路径都返回值”。但是在我的例子中,throwsspecificfault()总是抛出(适当的)异常。所以我不得不在最后加上一个返回值,但这很难看 此模式的目的首先是因为“process()”是对外部web服务的调用

我有一个方法像

int f() {
  try {
    int i = process();
    return i;
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
}
这会产生一个编译器错误,“并非所有代码路径都返回值”。但是在我的例子中,throwsspecificfault()总是抛出(适当的)异常。所以我不得不在最后加上一个返回值,但这很难看

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

有更干净的方法吗?

没有

想象一下,如果在单独的DLL中定义了
ThrowSpecificFault

如果修改DLL以不引发异常,然后在不重新编译的情况下运行程序,会发生什么情况?

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

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

  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return i;
}
下面的代码将执行您正在查找的操作,并始终返回一个整数

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

  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return i;
}
把return语句放在函数的末尾,你就没事了

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

如何:

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

我建议您将通过特定故障(ex)转换为通过特定故障(ex);
SpecificFault
方法将返回要抛出的异常对象,而不是将其本身抛出。干净多了


这是(查找文本“使用异常生成器方法”)建议的模式。

您有三个选项:

始终返回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);
    }
}
int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}
从方法返回异常并抛出:

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);
    }
}
int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}
或创建自定义异常类并抛出:

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);
    }
}
int f() {
    try {
        int i = process();
        return i;
    } catch(Exception ex) {
        throw new SpecificFault(ex);
    }
}

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


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

我想您可以让ThrowSpecificFault返回一个对象,然后可以

return ThrowSpecificFault(ex)
否则,您可以将ThrowSpecificFault重写为异常子类型的构造函数,也可以将ThrowSpecificFault创建到创建异常但不抛出异常的工厂中。

您可以这样做:

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
int f() 
{
    // no need to try-catch any more, here or anywhere else...
    int i = process();
    return i;
}
var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();

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

试试这个

int f() {
  try {
    return process();
  } catch(Exception ex) {
    ThrowSpecificFault(ex);
  }
  return -1;
}
您还可以使用throw关键字

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

但是该方法应该返回一些异常,而不是抛出它

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

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
int f() 
{
    // no need to try-catch any more, here or anywhere else...
    int i = process();
    return i;
}
var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();

下一步需要做的就是定义一个拦截处理程序,您可以定制该处理程序来处理异常。使用此处理程序,您可以处理应用程序中引发的所有异常。这样做的好处是,您不再需要用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实例化对象,如下所示:

catch (Exception ex)
{
    Exception e = CreateSpecificFault(ex);
    throw e;
}
int f() 
{
    // no need to try-catch any more, here or anywhere else...
    int i = process();
    return i;
}
var objectToUse = myUnityContainer.Resolve<MyObjectToUse>();
var objectToUse=myUnityContainer.Resolve();
更多关于团结的信息。拦截:


现在退货类型可以是一种类型,也可以是“void”,意思是“无退货类型”。理论上,我们可以添加第二个特殊的返回类型“never”,它具有您想要的语义。包含对“从不”返回方法的调用的表达式语句的端点将被视为不可访问,因此在C#中的任何上下文中,如果“goto”、“throw”或“return”是合法的,则该语句都是合法的


现在,十年后,将其添加到类型系统中的可能性很小。下次从头开始设计类型系统时,请记住包含“从不”类型。

由于.Net Standard 2.1和.Net Core 3.0,您可以使用。 这是斯蒂芬·图布的


遗憾的是,如果没有一个不幸的内部消息,这可能会与[StackTraceHidden]结合在一起。这可能会在的帮助下发生变化。

相关:我留下这个作为答案,但罗伯特·格雷纳击败了我。+1,这是微软指南中推荐的模式。我确实:;找到文本“使用异常生成器方法”。这是一个真正的解决方案。在我看来,其他一切都只是昙花一现。我也有同样的问题,这个选项是无效的。因为在我的例子中,“ThrowSpecificFault”是一个之前已经定义过的对象,并且有一些数据。所以我希望这个对象抛出一个异常和他拥有的数据。不幸的是,这是一个简单的答案,通常是有效的(对于简单的例子也是有效的),但是,如果您每次都尝试做一些日志记录,并尝试将其包装到一个函数中以实现可重用性,那么将完全失败。如果修改Foo以返回long而不是int,然后运行调用Foo的程序而不重新编译它,会发生什么?没什么好的。在外部库中更改方法的签名,然后在不重新编译的情况下继续使用它是不正确的。这就是为什么我们在程序集上有版本戳记等。@Eric-我相信SLaks假设的情况不需要更改签名,所以这显然不是一个突破性的更改。@kvb:据我所知,建议的功能,是为了捕捉这样一个事实,即一个方法永远不会在其签名中返回。@Eric:虽然该功能可以解决OPs问题,但我没有得到OP看起来是f的印象