.net Try-Catch错误处理的最佳实践

.net Try-Catch错误处理的最佳实践,.net,exception,exception-handling,.net,Exception,Exception Handling,我试图避免在捕获时返回错误的值,但我很难找到比此更好的解决方案: private SecurityLevel ApiGetSecurityLevel() { try { return _BioidInstance.GetSecurityLevel(); } catch { return SecurityLevel.High; }

我试图避免在捕获时返回错误的值,但我很难找到比此更好的解决方案:

    private SecurityLevel ApiGetSecurityLevel()
    {
        try
        {
            return _BioidInstance.GetSecurityLevel();
        }
        catch
        { 
            return SecurityLevel.High;
        }
    }

有没有更好的方法来避免返回错误的值?我无法更改SecurityLevel枚举。

您不能返回任何内容。并使您的函数在查看结果时,就好像ApiGetSecurityLevel()什么都不是一样

不要捕获异常。允许异常“冒泡”以强制调用者/调用者处理默认安全值的设置。


如果确实要返回值,请使用
Nullable
SecurityLevel?

private SecurityLevel? ApiGetSecurityLevel() { 
    try { 
        return _BioidInstance.GetSecurityLevel(); 
    } 
    catch {  
        return null; 
    } 
} 
然后用作:

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

在这种情况下,应用程序可能会失败吗?也就是说,如果无法确定SecurityLevel,用户应该无法继续

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


如果应用程序应该能够继续,选择(并记录)一些默认值,然后完全按照您正在做的操作。

您可以让异常冒泡出来。

除了Matt的答案之外,让异常发生有什么错?如果应用程序中的状态或访问无效,最好干脆将其终止。

如果可以更改函数的返回类型,我会将其更改为可为null的枚举,并在catch中返回null

private SecurityLevel? ApiGetSecurityLevel()
{
    try
    {
        return _BioidInstance.GetSecurityLevel();
    }
    catch
    { 
        return null;
    }
}
private SecurityLevel? ApiGetSecurityLevel()
{
    try
    {
        return _BioidInstance.GetSecurityLevel();
    }
    catch
    { 
        return null;
    }
}

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

其次,这不是try/catch的好用法。Try/catch不得用于正常控制流,仅用于例外情况

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

private SecurityLevel ApiGetSecurityLevel()
    {
        object securityLevel = _BioidInstance.GetSecurityLevel();
        if (securityLevel is SecurityLevel)
        {
             return _BioidInstance.GetSecurityLevel();
        }
        else
        {
             throw new Exception("Invalid SecurityLevel");
        }
    }
然后将其与if一起使用,如果返回false,则让处理代码决定其BioId的默认securitylevel


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

如果你可以在
SecurityLevel
/
中添加
NotSet
枚举,然后,您可以从catch块返回它。在无法确定升级隐私时返回它们是一个非常奇怪的选择

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

如果在枚举中定义了安全级别,它将返回_BioidInstance中的安全级别,否则将返回SecurityLevel.High


如果是我,如果我知道安全级别不能超出枚举中定义的范围,我只会不使用try-catch,如果遇到它,就让它失败。这样,我知道其他地方出了问题,我可以去修复它。

在这种情况下,安全性变成了二进制

举一个安全化合物的例子,在大门处,要么有人可以进去,要么没有人。如果他们没有达到安全级别,该人员不应通过大门

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

我将彻底废除这种方法,并用更接近的方法取代它

private bool HasSecurityLevel(SecurityLevel securityLevel) 
{ 
    try 
    { 
        return _BioidInstance.GetSecurityLevel() == securityLevel; 
    } 
    catch 
    {  
        return false; 
    } 
} 
然后根据需要检查每个安全级别


这样做的理由是,在某个时候必须进行检查,也可以使其尽可能接近源代码(在第一次获得安全级别时)。

是的。这是对挡块的滥用。它们用于捕获特定的异常。但是,请尝试使用IsNot而不是Not object IsNothing。他说SecurityLevel是一个枚举,所以Nothing(C#中的
null
)不是有效值。@Justin
Nothing
将等同于C中的
default(SecurityLevel)
,在这个例子中,对什么是“正确值”进行了一点解释如果捕获到异常,是否可以?除了SecurityLevel枚举中的内容外,您的安全级别是否可以设置为其他任何内容?这是一个失败致命的例程。它应该是故障安全的:返回SecurityLevel.None;您希望GetSecurityLevel()调用引发什么样的异常?假设他想在if中验证返回值之前缓存该返回值,否则他将不得不再次运行该返回值以检索该值,这可能意味着另一次DB命中。@Jimmy Hoffa,不理解您的评论。打什么?什么指示给你的印象是OP想要缓存返回?如果他不想缓存方法的返回,他会让方法返回true或false,而不是一个可识别的值。@Jimmy Hoffa:我觉得很傻,但我仍然不明白你的意思。他为什么要缓存该值?该方法显然用于返回安全级别,然后将其与
SecurityLevel
枚举进行比较。异常仅在异常情况下抛出,也就是说,不太常见。因此,如果使用得当,它们对性能没有影响。无论如何,这不是答案,因为它们需要返回该级别,而不是布尔值。也许您希望将其作为输出参数并使用Try隐喻。或者,更好的方法是捕获它并将其作为
AuthorizationException
的内部异常重新显示。不管是哪种方式,失败时都会出现异常,而不是返回值。所有这一切所做的就是向上推异常:当他们取消引用该值时,它将抛出异常。
SecurityLevel sec = _BioidInstance.GetSecurityLevel();
return (Enum.IsDefined(Typeof(SecurityLevel), sec) ? sec : SecurityLevel.High);
private bool HasSecurityLevel(SecurityLevel securityLevel) 
{ 
    try 
    { 
        return _BioidInstance.GetSecurityLevel() == securityLevel; 
    } 
    catch 
    {  
        return false; 
    } 
}