C#函数是否有标准的"永不返回"属性?

use*_*472 30 c# attributes exception return-type

我有一个看起来像这样的方法:

void throwException(string msg)
{
    throw new MyException(msg);
}
Run Code Online (Sandbox Code Playgroud)

现在,如果我写

int foo(int x, y)
{
    if (y == 0)
        throwException("Doh!");
    else
        return x/y;
}
Run Code Online (Sandbox Code Playgroud)

编译器会抱怨foo"并非所有路径都返回一个值".

是否有一个属性我可以添加到throwException以避免这种情况?就像是:

[NeverReturns]
void throwException(string msg)
{
    throw new MyException(msg);
}
Run Code Online (Sandbox Code Playgroud)

我担心自定义属性不会这样做,因为为了我的目的,我需要编译器的合作.

ber*_*hof 32

为什么不改变它

int foo(int x, y)
{
    if (y == 0)
        throwException("Doh!");
    return x/y;
}
Run Code Online (Sandbox Code Playgroud)

这给出了相同的运行时结果,编译器不会抱怨.


Dav*_*d M 22

不.我建议您更改第一个函数的签名以返回异常而不是抛出异常,并将throw语句保留在第二个函数中.这将使编译器保持高兴,并且闻起来也不那么糟糕.

  • 我会称这是一个例外工厂,这根本没有味道. (4认同)
  • 这是好习惯吗?除了抛出它之外,我从未见过使用Exception对象做过的任何事情. (3认同)
  • 如果你需要以更复杂的方式构建异常,比如包装它并添加其他信息,我会说这是一个很好的做法.该方法应重命名.有一个方法只会引发异常,我看不出任何意义. (2认同)

Chr*_*ter 10

伯恩霍夫的回答是正确的.但是,如果您在实例化异常时尝试封装大量逻辑,那么您需要做的就是更改代码:

void throwException(string msg) {
    throw new MyException(msg);
}
Run Code Online (Sandbox Code Playgroud)

对此:

Exception makeException(string msg) {
    return new MyException(msg);
}
Run Code Online (Sandbox Code Playgroud)

那么你的调用代码将如下所示:

int foo(int x, y) {
    if (y == 0) {
        throw makeException("Doh!");
    }
    return x / y;
}
Run Code Online (Sandbox Code Playgroud)

在所有其他条件相同的情况下,更喜欢功能代码到程序代码.它更容易重复使用和单元测试.

编辑:

根据Fred的示例代码,这就是我要做的.这不是代码合同,但它仍然有效.

private int getVarID(string s_varID) {
    int varID;
    if(s_varID == "ILT") {
        return 123;
    } else if(s_varID == "TL") {
        return 456;
    } else if(s_varID == "FT") {
        return 789;
    } else if(int.TryParse(s_varID, out varID)) {
        return varID;
    } else {
        throw makeParseError("varID must be an integer or 'ILT', 'TL' or 'FT'.");
    }
}
Run Code Online (Sandbox Code Playgroud)


MBe*_*ley 7

[DoesNotReturn]in的属性System.Diagnostics.CodeAnalysis应该是你想要的。

参考:https : //docs.microsoft.com/en-us/dotnet/api/system.diagnostics.codeanalysis.doesnotreturnattribute?view=netcore-3.1


Joe*_*ams 5

您可以通过使用泛型来声明函数返回"任何内容"来指示"永不返回":

T ThrowException<T>(string msg)
{
    throw new MyException(msg);
}
Run Code Online (Sandbox Code Playgroud)

所以现在你可以写:

int foo(int x, int y)
{
    if (y == 0)
        return ThrowException<int>("Doh!");
    else
        return x/y;
}
Run Code Online (Sandbox Code Playgroud)

这个成语用于像HaskellF#这样的语言,并且基于爆炸原理,也被称为"ex falso quodlibet".原因是:如果一个函数永远不会返回,那么我们可以对它的返回值做出我们想要的任何神奇假设,因为这样的值永远不会存在.这里,调用者(foo)假设ThrowException将返回一个int.

一些小缺点:

  • 实施ThrowException可以通过返回来绕过这个default(T).
  • 调用时必须指定返回类型ThrowException(Haskell和F#可以推断它).
  • 这个成语在C#中非常罕见,所以很多人都不会认出它.您可能需要添加评论,说明您正在做什么.

正如其他答案所说的那样,你可能最好还是退回异常而不是扔掉它.