and*_*ndy 12 .net error-handling exception
我的同事编写的许多代码库方法通常通过捕获,通知和日志记录来执行自己的错误处理.
在这些情况下,方法返回一个布尔值,表示成功或失败.
但有时候,如果方法失败,我希望调用代码知道原因,并且返回布尔值是不够的.
解决此问题的一种方法是在方法中保留错误处理,但使方法无效,并让方法抛出它们的异常.
然而,最近我养成了以适当的方法返回异常的习惯,通常是可能无效的动作方法,但我想知道动作的状态.
返回异常而不是使用void方法抛出异常的优点是我认为它使其他程序员更容易使用你的库,更重要的是,它意味着你可以安全地调用该方法而不必担心捕获例外
例如,如果方法只是无效,那么程序员应该可以立即处理成功或失败.
但是,如果方法专门指定了Exception的返回类型,那么您知道可以根据需要检查成功或失败.但这也意味着如果你不想,你不必担心捕获错误.
那有意义吗?也许我没有使用过最好的例子,但一般情况下,返回Exceptions是否可以,或者那里有更好的模式?
UPDATE
哇,压倒性的结果是没办法的.我是这么想的.我必须说,做它(返回一个例外)有点解决了一个问题,但确实感觉不对.
那么,从你的一些答案中,这些特定场景的最佳解决方案(复杂的类,或具有一个或多个外部依赖关系的类(即Web服务))似乎是一个自定义结果类?
更新:
我非常感谢所有的意见,我正在阅读所有内容,我正在仔细考虑所有的意见.
目前我喜欢使用void方法,抛出异常,然后在外面捕获它们......那更好吗?
JP *_*oto 32
如果你的意思是......
public Exception MyMethod( string foo )
{
if( String.IsNullOrEmpty() )
{
return new ArgumentNullException( "foo" );
}
}
Run Code Online (Sandbox Code Playgroud)
... 而不是 ...
public void MyMethod( string foo )
{
if( String.IsNullOrEmpty() )
{
throw new ArgumentNullException( "foo" )
}
}
Run Code Online (Sandbox Code Playgroud)
那绝对不是,这样做是不对的.您将完全重新发明异常的目的并将其用作结果.以下是一些标准的最佳实践.
另一个很好的理由不是标准代表将不再匹配您的方法签名.因此,例如,您无法再使用Action<string>MyMethod而需要使用它Func<string,Exception>.
@Andy,评论,回答太长时间评论:不是真的.不要那么关心来电者.无论如何,他应该在设计中保持防守.想想Exception的语义......"除非有人知道如何解决这个问题,否则这个应用程序的执行将会停在这里." 如果您可以解决此问题,则应解决该问题.如果你不能,你必须记录它并将它扔到一个新的水平,因为他们可能知道该做什么.
你应该处理你可以处理的事情并抛弃你不能处理的东西.根据定义,调用堆栈中的人比你更了解世界.您的应用程序需要具备弹性,能够处理异常并继续运行.他们唯一的方法是采取防御性编码,并将问题推向更高级别的信息,以确定是否可以做任何事情.
如果答案是"否",那么在一天结束时,将问题记录到它可以被理解,成为一个好的公民,并优雅地终止应用程序,并在另一天生活.不要自私,并尝试为您的来电者隐藏错误.要防守,他也会这样做.:)
查看Enterprise Library Exception处理块.它认为他们真正阐述了如何在整个架构中处理异常的伟大愿景.
Edd*_*die 13
没有人说过这个:我的理解是在.NET中,在抛出异常之前,不会填充异常的堆栈跟踪.请参阅处理例外情况的最佳做法,其中说:
堆栈跟踪从抛出异常的语句开始,并以捕获异常的catch语句结束.在决定将throw语句放在何处时,请注意这一事实.
使用异常构建器方法.一个类在其实现中从不同的地方抛出相同的异常是很常见的.要避免过多的代码,请使用创建异常的辅助方法并将其返回.
在.NET中,如果您只是实例化一个Exception并返回它,那么您将不会在该Exception中拥有任何堆栈信息.当您使用此功能创建"异常"构建器方法时,这是一个好处,当您按照要求的方式使用"异常"时会丢失.相比之下,在Java中,在实例化Exception时添加堆栈信息,无论是否抛出它.
因此,在.NET中,当您返回一个从未抛出的异常时,您放弃了堆栈跟踪,告诉您问题发生的位置.在这种情况下,也许你不在乎,但我认为值得指出.
在任何现代JVM和任何最新的.NET版本中,抛出异常的性能开销都相当小.返回异常而不是抛出异常 - 出于性能原因 - 是不恰当的优化... 除非你已经分析了你的程序并发现特定的抛出确实是一个瓶颈,并且返回异常会产生有意义的差异.(这会让我感到惊讶,但一切皆有可能.)
注意:假设您创建了一个方法,否则将void返回错误异常.这意味着如果要检查错误,则必须检查null是否存在错误.作为一般规则,在出错时返回null的方法会导致脆弱的代码.例如,返回List的方法应该返回一个空List而不是null.
另请注意,在.NET中重新抛出异常时,由于堆栈是在throw子句中填充的,因此通常会丢失原始堆栈跟踪.要避免这种情况,请使用bare throw而不指定Exception实例.如果你throw ex那么你将丢失原始堆栈跟踪.
你永远不应该返回异常.相反,如果您的函数足够复杂,请创建一个类,该类是您的函数的结果.例如,GetPatientList方法返回GetPatientListResult.它可能有一个成功的成员.例外是非常罕见的东西,例如文件在操作中消失,为函数设置无效或空参数,数据库关闭.此外,它打破了整个抽象模型 - Dog.GoForAWalk应该返回DogWalkReport,而不是PossiblyNullDogWalkException.
没有.
例外应该是仅在特殊情况下存在的事物(因此名称).我唯一能看到让方法返回异常的方法是某种类型的工厂方法,其目的是专门创建异常 - 但即便如此,它仍在延伸.
如果需要返回比布尔值更多的信息,请创建一个包含布尔值+其他信息的自定义类(不是从异常派生).
绝对是非正统的例外使用.使异常变得强大的特性是抛出的异常会在调用堆栈中冒出任意数量的层.如果您只是将其退回,则会失去该属性(但也会失去与此相关的负面性能影响).
我真的没有看到这与简单地返回包含有关可能错误的信息的类的实例有何不同.唯一的区别是返回从Exception类继承的对象可能会在以后读取代码的其他开发人员中引起一些混淆.
因此,虽然返回包含有关错误的信息的对象没有任何问题,但为了避免混淆,我建议使用不从Exception继承的类.
在您描述的场景中返回异常是一个坏主意,因为异常不是为此目的而设计的.
最好创建一个包含所需信息的结构或类,然后返回它.
public enum MyErrorType
{
Abc,
Xyz,
Efg
};
public struct Result
{
public bool Success;
public MyErrorType ErrorType;
};
Run Code Online (Sandbox Code Playgroud)
然后方法:
private Result MyMethod()
{
// code
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4637 次 |
| 最近记录: |