关于.net:Try Catch错误处理的最佳实践

Best Practice for Try Catch Error Handling

我试图避免在catch中返回不正确的值,但找不到比此更好的解决方案:

1
2
3
4
5
6
7
8
9
10
11
    private SecurityLevel ApiGetSecurityLevel()
    {
        try
        {
            return _BioidInstance.GetSecurityLevel();
        }
        catch
        {
            return SecurityLevel.High;
        }
    }

有没有更好的方法这样做,我就不会返回错误的值?我无法更改SecurityLevel枚举。


不要捕获异常。允许异常"冒泡",以强制调用方/调用方处理设置默认安全值的操作。

如果您真的想返回一个值,那么使用NullableSecurityLevel?

1
2
3
4
5
6
7
8
private SecurityLevel? ApiGetSecurityLevel() {
    try {
        return _BioidInstance.GetSecurityLevel();
    }
    catch {  
        return null;
    }
}

然后使用AS:

1
2
3
if (ApiGetSecurityLevel().HasValue == false) {
    // use default security level
}


是否有可能是应用程序失败的情况?也就是说,如果不能确定安全级别,用户就不能继续?

如果是这样,为什么不重新抛出并让用户界面处理它(或者让它被记录下来,不管你的商店如何工作)?

如果应用程序应该能够继续,那么选择(并记录)一些默认值,并执行您正在执行的操作。


首先,只要GetSecurityLevel返回SecurityLevel,就没有理由尝试/捕获。编译器将在那里捕获任何问题。

第二,这不是一个很好的尝试/捕获的用途。Try/Catch不应用于正常控制流,仅用于例外情况。

如果出于某种原因,getSecurityLevel()不返回SecurityLevel枚举类型:

1
2
3
4
5
6
7
8
9
10
11
12
private SecurityLevel ApiGetSecurityLevel()
    {
        object securityLevel = _BioidInstance.GetSecurityLevel();
        if (securityLevel is SecurityLevel)
        {
             return _BioidInstance.GetSecurityLevel();
        }
        else
        {
             throw new Exception("Invalid SecurityLevel");
        }
    }

如果您可以更改foction的返回类型,我会将其更改为可为空的枚举,并在catch中返回空值。

1
2
3
4
5
6
7
8
9
10
11
private SecurityLevel? ApiGetSecurityLevel()
{
    try
    {
        return _BioidInstance.GetSecurityLevel();
    }
    catch
    {
        return null;
    }
}


除了马特的回答,让例外发生有什么错?如果您的应用程序中存在状态或访问的某些无效性,那么最好直接终止它。


你可以让例外情况浮出水面。


你什么也不能还。并使您的函数看起来结果好像apigetSecurityLevel()不是什么


在这种情况下,安全性变为二进制。

举一个安全化合物的例子,在门上,要么有人能进去,要么就不能进去。如果他们不能达到安全级别,那人就不应该通过门。

如果getSecurityLevel()方法抛出异常,则会在入口处关闭某些内容。然后授予一些任意的安全级别并允许它们通过不是一个好主意。

我会完全放弃这个方法,用更接近

1
2
3
4
5
6
7
8
9
10
11
private bool HasSecurityLevel(SecurityLevel securityLevel)
{
    try
    {
        return _BioidInstance.GetSecurityLevel() == securityLevel;
    }
    catch
    {  
        return false;
    }
}

然后根据需要检查每个安全级别。

这样做的合理性是在某个时刻必须进行检查,也可以使其尽可能靠近源(当第一次获得安全级别时)。


1
2
SecurityLevel sec = _BioidInstance.GetSecurityLevel();
return (Enum.IsDefined(Typeof(SecurityLevel), sec) ? sec : SecurityLevel.High);

如果在枚举中定义了安全级别,它将返回_bioidinstance中的安全级别,否则将返回security level.high。

如果是我,如果我知道安全级别不能是枚举中定义的以外的任何东西,那么我只需要不使用try-catch就可以了,如果涉及到它,就让它失败。这样我就知道别的地方出了问题,我可以去修理它。


如果可以向SecurityLevel中添加Nothing/NotSet枚举,则可以从catch块返回该枚举。当你不能确定升级后的私隐是一个非常奇怪的选择。

或者,返回SecurityLevel作为可以为空的枚举。

1
2
3
4
5
6
7
8
9
10
11
private SecurityLevel? ApiGetSecurityLevel()
{
    try
    {
        return _BioidInstance.GetSecurityLevel();
    }
    catch
    {
        return null;
    }
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class BioId { public SecurityLevel SecLevel { get; set; } }

private bool ApiGetSecurityLevel(BioId bioId)
{
    try
    {
        bioIdSecLevel = bioId.GetSecurityLevel();
        return true;
    }
    catch (PossibleException)
    {
        return false;
    }
}

然后将其与if和if一起使用,如果返回false,那么让处理代码决定其bioid的默认安全级别。

尽管我同意其他人的观点,但实际上,你只想让异常冒泡,让高层来处理它们。尽管有时有标准不允许例外冒泡,因为它们冒泡通过的每一层都会明显影响性能,但我要说的是,无论如何,你不应该有太多的层,洋葱是复杂的,就像食人魔一样。