2010-10-08 86 views
15

我有一个方法,像...声明一个方法总是抛出一个异常?

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

这将产生一个编译器错误,“不是所有的代码路径返回一个值”。但在我的情况下,ThrowSpecificFault()将始终抛出(适当的)异常。所以我被迫在最后放置一个返回值,但这很丑陋。

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

任何更干净的方式来做到这一点?

+1

相关:[是否有标准的“从不返回”属性的C#函数?](http://stackoverflow.com/questions/1999181/is-there-a-standard-never-returns-attribute-for-c函数) – 2010-10-08 17:42:19

回答

47

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

这是由Microsoft's guidelines推荐的模式(找到“使用异常生成器方法”文本)。

+5

+1,这是微软指南中推荐的模式。 – Joe 2010-10-08 17:43:45

+0

你有链接吗? – noctonura 2010-10-08 17:55:15

+2

我这样做:http://msdn.microsoft.com/en-us/library/seyhszts.aspx;找到“使用异常生成器方法”文本。 – CesarGon 2010-10-08 18:06:35

3

想像一下,如果在ThrowSpecificFault一个单独的DLL中定义。 如果您修改DLL以避免引发异常,那么运行您的程序时不要重新编译它,会发生什么情况?

+3

想象一下,如果方法Foo是在单独的DLL中定义的。如果修改Foo返回一个long而不是int,那么运行调用Foo的程序而不重新编译它,会发生什么? *没什么好的*。它永远不会正确地改变外部库中方法的签名,然后继续使用它而不用重新编译。这就是为什么我们在组件上有版本印章等。 – 2010-10-08 18:49:00

+0

@Eric - 我相信SLaks的假设情况并不需要改变签名,所以它不是一个明显的突破性改变。 – kvb 2010-10-10 13:44:56

+2

@kvb:据我所知,建议的功能是捕获一个事实,即一个方法在其签名*中永远不会返回*。 – 2010-10-10 15:32:36

8

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

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

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

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

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

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

+0

+1你打我一分钟! – 2010-10-08 17:42:02

1

如何:

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

我要离开这个作为答案,但罗伯特格雷纳击败了我。 – 2010-10-08 17:42:54

2

你有三个选择:

总是返回我,但前声明它:

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

是的。

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

它实际上更有意义。您不会为“正常”流程使用异常,因此如果每次都抛出异常,则异常将成为规则。在功能创建特定的异常,并在这里把它,因为它是一个例外,这里的流量..

0

我想你可以做ThrowSpecificFault返回一个对象,然后你可以

return ThrowSpecificFault(ex)

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

3

你可以这样做:

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

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

试试这个

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

您也可以使用throw关键字

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

但随后这个方法应该返回一些异常,而不是把它扔的。

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

7

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

现在很可能不会将它添加到类型系统中,十年以后。下次从零开始设计类型系统时,请记住包含“从不”类型。

相关问题