cor*_*ttk 528 c# exception-handling try-catch
这篇文章包括这段代码:
public static string SerializeDTO(DTO dto) {
try {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
catch(Exception ex) {
throw ex;
}
}
Run Code Online (Sandbox Code Playgroud)
本文的其余部分看起来很合理(对于菜鸟),但是try-catch-throw会抛出一个WtfException ... 这不完全等同于根本不处理异常吗?
人机工程学:
public static string SerializeDTO(DTO dto) {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
Run Code Online (Sandbox Code Playgroud)
或者我错过了C#中错误处理的基本内容?它与Java几乎相同(减去已检查的异常),不是吗?......也就是说,他们都改进了C++.
Stack Overflow问题重新抛出无参数捕获和不执行任何操作之间的区别?似乎支持我的观点,即try-catch-throw是一个无操作.
编辑:
只是为了总结未来发现这个主题的人...
不要
try {
// Do stuff that might throw an exception
}
catch (Exception e) {
throw e; // This destroys the strack trace information!
}
Run Code Online (Sandbox Code Playgroud)
堆栈跟踪信息对于确定问题的根本原因至关重要!
做
try {
// Do stuff that might throw an exception
}
catch (SqlException e) {
// Log it
if (e.ErrorCode != NO_ROW_ERROR) { // filter out NoDataFound.
// Do special cleanup, like maybe closing the "dirty" database connection.
throw; // This preserves the stack trace
}
}
catch (IOException e) {
// Log it
throw;
}
catch (Exception e) {
// Log it
throw new DAOException("Excrement occurred", e); // wrapped & chained exceptions (just like java).
}
finally {
// Normal clean goes here (like closing open files).
}
Run Code Online (Sandbox Code Playgroud)
在不太具体的异常之前捕获更具体的异常(就像Java一样).
参考文献:
Fre*_*örk 414
第一; 文章中代码的表现方式是邪恶的.throw ex
将异常中的调用堆栈重置为此throw语句的位置; 丢失有关实际创建异常的位置的信息.
第二,如果你只是抓住并重新抛出这样的东西,我认为没有附加价值,上面的代码示例在throw ex
没有try-catch的情况下也会同样好(或者,有点,甚至更好).
但是,在某些情况下,您可能希望捕获并重新抛出异常.记录可能是其中之一:
try
{
// code that may throw exceptions
}
catch(Exception ex)
{
// add error logging here
throw;
}
Run Code Online (Sandbox Code Playgroud)
Eoi*_*ell 112
不要这样做,
try
{
...
}
catch(Exception ex)
{
throw ex;
}
Run Code Online (Sandbox Code Playgroud)
您将丢失堆栈跟踪信息......
要么,
try { ... }
catch { throw; }
Run Code Online (Sandbox Code Playgroud)
要么
try { ... }
catch (Exception ex)
{
throw new Exception("My Custom Error Message", ex);
}
Run Code Online (Sandbox Code Playgroud)
您可能想要重新抛出的原因之一是,如果您正在处理不同的例外,例如
try
{
...
}
catch(SQLException sex)
{
//Do Custom Logging
//Don't throw exception - swallow it here
}
catch(OtherException oex)
{
//Do something else
throw new WrappedException("Other Exception occured");
}
catch
{
System.Diagnostics.Debug.WriteLine("Eeep! an error, not to worry, will be handled higher up the call stack");
throw; //Chuck everything else back up the stack
}
Run Code Online (Sandbox Code Playgroud)
bzl*_*zlm 55
C#(在C#6之前)不支持CIL"过滤异常",这是VB所做的,所以在C#1-5中重新抛出异常的一个原因是你在catch()时没有足够的信息确定是否要实际捕获异常.
例如,在VB中你可以做到
Try
..
Catch Ex As MyException When Ex.ErrorCode = 123
..
End Try
Run Code Online (Sandbox Code Playgroud)
...它不会处理具有不同ErrorCode值的MyExceptions.在v6之前的C#中,如果ErrorCode不是123,则必须捕获并重新抛出MyException:
try
{
...
}
catch(MyException ex)
{
if (ex.ErrorCode != 123) throw;
...
}
Run Code Online (Sandbox Code Playgroud)
从C#6.0开始,您可以像使用VB一样进行过滤:
try
{
// Do stuff
}
catch (Exception e) when (e.ErrorCode == 123456) // filter
{
// Handle, other exceptions will be left alone and bubble up
}
Run Code Online (Sandbox Code Playgroud)
小智 14
我的主要原因是:
try
{
//Some code
}
catch (Exception e)
{
throw;
}
Run Code Online (Sandbox Code Playgroud)
是这样我可以在catch中有一个断点,它有一个实例化的异常对象.我在开发/调试时做了很多.当然,编译器会对所有未使用的e发出警告,理想情况下,它们应该在发布版本之前删除.
他们在调试时很好.
edo*_*oft 11
重新抛出异常的正当理由可能是您希望向异常添加信息,或者可能将原始异常包装在您自己的异常中:
public static string SerializeDTO(DTO dto) {
try {
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
xmlSer.Serialize(sWriter, dto);
return sWriter.ToString();
}
catch(Exception ex) {
string message =
String.Format("Something went wrong serializing DTO {0}", DTO);
throw new MyLibraryException(message, ex);
}
}
Run Code Online (Sandbox Code Playgroud)
小智 6
当您为库或 dll 编程函数时,这会很有用。
此重新抛出结构可用于有目的地重置调用堆栈,这样您就不会看到从函数内部的单个函数抛出的异常,而是从函数本身获取异常。
我认为这只是用来使抛出的异常更干净,并且不会进入库的“根”。
人们没有提到的一点是,虽然.NET语言并没有真正做出恰当的区分,但是一个人是否应该在发生异常时采取行动以及是否会解决它的问题实际上是截然不同的问题.在许多情况下,人们应该根据无法解决的异常采取行动,并且在某些情况下,"解决"异常所需的一切都是将堆栈展开到某一点 - 不需要进一步的操作.
由于人们应该只"抓住"可以"处理"的事物的共同智慧,许多应该在异常发生时采取行动的代码不会.例如,许多代码将获取锁,将受保护的对象"暂时"置于违反其不变量的状态,然后将其置于合法状态,然后在其他任何人都可以看到该对象之前释放锁定.如果在对象处于危险无效状态时发生异常,通常的做法是在对象仍处于该状态时释放锁定.一个更好的模式是在对象处于"危险"状态时发生异常,明确地使锁无效,因此将来任何获取它的尝试都将立即失败.
在大多数.NET语言中,代码基于异常采取操作的唯一方法是catch
它(即使它知道它不会解决异常),执行有问题的操作然后重新执行throw
.如果代码不关心抛出什么异常,另一种可能的方法是使用ok
带有try/finally
块的标志; 将ok
标志设置为false
块之前,并且true
在块退出之前,以及在块中的任何之前return
.然后,在内部finally
,假设如果ok
未设置,则必须发生异常.这种方法是语义上比一个更好的catch
/ throw
,而是丑陋和比它应该是少维护.
归档时间: |
|
查看次数: |
207758 次 |
最近记录: |