C# NET异常处理有多严重?
有时我会遇到这样的情况:将整段代码封装在try-catch块中比执行大量检查更容易,这会严重降低代码的可读性。 比如说这个,C# NET异常处理有多严重?,c#,.net,error-handling,try-catch,C#,.net,Error Handling,Try Catch,有时我会遇到这样的情况:将整段代码封装在try-catch块中比执行大量检查更容易,这会严重降低代码的可读性。 比如说这个, var result = string.Empty; if (rootObject != null) { if (rootObject.FirstProperty != null) { if (rootObject.FirstProperty.SecondProperty != null) { if
var result = string.Empty;
if (rootObject != null)
{
if (rootObject.FirstProperty != null)
{
if (rootObject.FirstProperty.SecondProperty != null)
{
if (!string.IsNullOrEmpty(rootObject.FirstProperty.SecondProperty.InterestingString))
{
result = rootObject.FirstProperty.SecondProperty.InterestingString;
}
}
}
}
我真的更喜欢这样做
var result = string.Empty;
try
{
result = rootObject.FirstProperty.SecondProperty.InterestingString;
}
catch { }
但在代码审查之后,我经常从我的导师那里听到,当可能进行简单检查时,我应该避免尝试捕获块。它是否真的如此关键,每个try-catch块都会消耗大量系统资源(相对而言)?这些资源是否仅在出现错误或每个案例(成功与否)同样“严重”时使用?这取决于
如果
rootObject
等很可能为空,那么使用第一种方法对其进行编码会更好,因为它不是一种例外情况。但是,它会使方法的执行稍微慢一点。尽管有一些方法可以重新编码嵌套的if
语句,以避免深度嵌套并允许快速退出方法
另一方面,如果正常执行速度是一个问题,并且rootObject
etc不太可能为空,那么使用第二种方法对其进行编码会更好,因为它**是并且是异常情况
您需要分析您的系统,以确定哪种方法更适合您的应用程序。例外情况适用于。。嗯,特殊情况。它们是为发生无法计划的事情而设计的。异常有一定的开销,使用它们来捕获像这样的一般问题被认为是不好的做法,特别是如果您只是忽略异常的结果(使用空的catch块)
它们可能会使代码看起来更干净,但不会使代码执行更干净。帮助可读性的一种方法是改变您的条件:
var result = string.Empty;
if (rootObject == null) return result;
if (rootObject.FirstProperty == null) return result;
if (rootObject.FirstProperty.SecondProperty == null) return result;
if (!string.IsNullOrEmpty(rootObject.FirstProperty.SecondProperty.InterestingString))
{
result = rootObject.FirstProperty.SecondProperty.InterestingString;
}
下一步是使用编译器将为您执行的条件快捷方式:
var result = string.Empty;
if (rootObject == null || rootObject.FirstProperty == null ||
rootObject.FirstProperty.SecondProperty == null) return result;
if (!string.IsNullOrEmpty(rootObject.FirstProperty.SecondProperty.InterestingString))
{
result = rootObject.FirstProperty.SecondProperty.InterestingString;
}
一种选择是使用。它们是执行您正在执行的检查类型的一种非常干净的方法,如果您正确配置调试构建,编译器实际上可以找到违反契约的代码。空的catch块确实不是一个好主意(并不是因为它会使用资源……出于很多原因,它不是一个好的编码)。如果您可以首先防止代码抛出异常,那么您就应该这样做 Try/Catch块在正确使用时很好使用(例如,当您访问代码无法控制的内容时,如打开网络连接) 如果您认为代码的某个部分中的错误不是致命的,那么还可以使用它们继续运行代码。只需确保正确处理catch块中的错误即可 但是,您应该考虑的一件事是编译器如何执行谓词 它将接受谓词最左边的子句,
rootObject!=null
,如果该值为false,并且它与您的其他子句相匹配,则该谓词的计算结果保证为false。编译器随后将忽略谓词的其余部分,因此您可以执行以下操作:
if (rootObject != null && rootObject.FirstProperty != null && rootObject.FirstProperty.SecondProperty != null && !string.IsNullOrEmpty(rootObject.FirstProperty.SecondProperty.InterestingString))
{
result = rootObject.FirstProperty.SecondProperty.InterestingString;
}
NET框架中的异常相对来说比较严重——值得花点力气来避免它们。毕竟,它们被称为例外——它们不应该是常见的 也就是说,它们远没有一些人想象的那么昂贵 在VisualStudio下调试时,当IDE调出捕获异常的行时,处理异常可能需要几秒钟的时间。正因为如此,一些人认为每一个异常都需要几秒钟来处理,因此必须不惜一切代价避免它们 我看到人们把系统性能差归咎于一个小时抛出几十个异常 这是一个神话。该系统完全能够每秒抛出和捕获数千个异常 也就是说,您可以使用以下几个简单的扩展函数整理原始代码:
var result
= rootObject.With( r => FirstProperty)
.With( r => r.SecondProperty)
.Return( r => r.InterestingString, string.Empty);
rootObject ...
rootObject.FirstProperty ...
rootObject.FirstProperty.SecondProperty ...
rootObject.FirstProperty.SecondProperty.InterestingString ...
if (rootObject != null)
{
var firstProperty = rootObject.FirstProperty;
if (firstProperty != null)
{
var secondProperty = firstProperty.SecondProperty;
if (secondProperty != null)
{
var interestingString = secondProperty.InterestingString;
if (!string.IsNullOrEmpty(interestingString))
{
result = interestingString;
}
}
}
}
其中,With
具有以下定义:
public static TResult With<TInput, TResult>(
this TInput o,
Func<TInput, TResult> evaluator)
where TResult : class
where TInput : class
{
if (o == null)
{
return null;
}
return evaluator(o);
}
异常是重量级还是轻量级完全无关抛出的异常很容易防止,这是一个bug。不要捕获异常:修复错误,这样您就不必捕获异常。异常处理 我不会担心像这样的代码中的异常“有多严重”。我稍后会解释原因 例外情况适用于例外情况。拥有异常处理程序意味着您希望这些属性永远不会为null 何时写入保护条件 这些属性为
null
是否常见
如果是这样,这不是一个例外情况。您应该编写适当的空测试,并将异常处理程序代码更改为空条件代码
这些属性为null
是否不常见,即您是否可以合理预期它们永远不会为null
如果是这样,您可以简单地避免编写null
检查,只让底层代码抛出。但是,对于哪个属性引发了异常,您不会得到很多上下文
您还可以执行null
检查并抛出更特定于上下文的异常
何时编写异常处理程序
如果这些属性为null
,则这是一种例外情况。但这并不意味着你必须有一个处理程序
在异常情况发生之前,您是否有一种简单的方法来测试它
如果是这样,那么您应该在允许您正在使用的底层代码引发异常之前对此进行测试。因为您只需检查null
,所以我认为这非常简单
你有合理的逻辑来处理这个级别的案件吗
如果您有合理的方法来处理该级别的异常情况,并且仍然保证您的方法
try
{
}
catch(Exception e)
{
logger.Log(e.ToString());
// ... eats the exeption
}
try
{
}
catch(Exception e)
{
logger.Log(e.ToString()); // Make sure your logger never throws...
throw; // Note: *not* `throw e;`
}
// Or:
try
{
}
catch
{
// Todo: Do something here, but be very careful...
throw;
}
try
{
}
catch(NullReferenceException e)
{
// ... Do whatever you want here ...
}
rootObject ...
rootObject.FirstProperty ...
rootObject.FirstProperty.SecondProperty ...
rootObject.FirstProperty.SecondProperty.InterestingString ...
var firstProperty = rootObject.FirstProperty;
var secondProperty = firstProperty.SecondProperty;
var interestingString = secondProperty.InterestingString;
if (rootObject != null)
{
var firstProperty = rootObject.FirstProperty;
if (firstProperty != null)
{
var secondProperty = firstProperty.SecondProperty;
if (secondProperty != null)
{
var interestingString = secondProperty.InterestingString;
if (!string.IsNullOrEmpty(interestingString))
{
result = interestingString;
}
}
}
}
rootObject.FirstProperty.SecondProperty.InterestingString
public class SomeClassUsingRoot
{
public string FindInterestingString()
{
return root != null
? root.FindInterestingString()
: null;
}
private RootSomething root;
}
public class RootSomething
{
public string FindInterestingString()
{
return FirstProperty != null
? FirstProperty.FindInterestingString()
: null;
}
public SomethingTopLevel FirstProperty { get; set; }
}
public class SomethingTopLevel
{
public string FindInterestingString()
{
return SecondProperty != null
? SecondProperty.InterestingString
: null;
}
public SomethingLowerLevel SecondProperty { get; set; }
}
public class SomethingLowerLevel
{
public string InterestingString { get; set; }
}