有什么区别
try { ... }
catch{ throw }
Run Code Online (Sandbox Code Playgroud)
和
try{ ... }
catch(Exception e) {throw new Exception(e.message) }
Run Code Online (Sandbox Code Playgroud)
无论第二个显示消息?
SLa*_*aks 250
throw;
重新抛出原始异常并保留其原始堆栈跟踪.
throw ex;
抛出原始异常但重置堆栈跟踪,销毁所有堆栈跟踪信息直到catch
阻塞.
throw ex;
throw new Exception(ex.Message);
更糟糕的是.它创建了一个全新的Exception
实例,丢失了异常的原始堆栈跟踪及其类型.(例如,IOException
).
此外,一些例外还包含其他信息(例如ArgumentException.ParamName
).
throw new Exception(ex.Message);
也将破坏这些信息.
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便您可以提供有关抛出异常时代码执行操作的其他信息.
为此,请定义一个继承的新类Exception
,添加所有四个异常构造函数,以及可选的另外一个构造函数,该构造函数接收InnerException
以及其他信息,并抛出新的异常类,作为参数传递ex
InnerException
.通过传递原始InnerException
,您可以保留所有原始异常的属性,包括堆栈跟踪.
Mar*_*ers 30
第一个保留原始堆栈跟踪:
try { ... }
catch
{
// Do something.
throw;
}
Run Code Online (Sandbox Code Playgroud)
第二个允许您更改异常的类型和/或消息和其他数据:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
Run Code Online (Sandbox Code Playgroud)
还有第三种传递内部异常的方法:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
Run Code Online (Sandbox Code Playgroud)
我建议使用:
Lee*_*Lee 14
这里的答案都没有显示出差异,这对于那些努力理解差异的人来说可能会有所帮助。考虑这个示例代码:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
生成以下输出:
using System;
using System.Collections.Generic;
namespace ExceptionDemo
{
class Program
{
static void Main(string[] args)
{
void fail()
{
(null as string).Trim();
}
void bareThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw;
}
}
void rethrow()
{
try
{
fail();
}
catch (Exception e)
{
throw e;
}
}
void innerThrow()
{
try
{
fail();
}
catch (Exception e)
{
throw new Exception("outer", e);
}
}
var cases = new Dictionary<string, Action>()
{
{ "Bare Throw:", bareThrow },
{ "Rethrow", rethrow },
{ "Inner Throw", innerThrow }
};
foreach (var c in cases)
{
Console.WriteLine(c.Key);
Console.WriteLine(new string('-', 40));
try
{
c.Value();
} catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如前面的答案中所示,裸露的抛出清楚地显示了失败的原始代码行(第 12 行)以及异常发生时调用堆栈中的其他两个活动点(第 19 行和 64 行)。
重新抛出案例的输出显示了为什么这是一个问题。当像这样重新抛出异常时,异常将不包含原始堆栈信息。请注意,仅throw e
包含(第 35 行)和最外层调用堆栈点(第 64 行)。如果以这种方式抛出异常,则很难找到问题的根源fail() 方法。
最后一个案例 (innerThrow) 最为复杂,包含的信息比上述任何一个案例都多。由于我们正在实例化一个新异常,因此我们有机会添加上下文信息(此处为“外部”消息,但我们也可以添加到新异常的 .Data 字典中)并保留原始异常中的所有信息异常(包括帮助链接、数据字典等)。
抛出一个新的异常会吹走当前的堆栈跟踪。
throw;
将保留原始堆栈跟踪并且几乎总是更有用。该规则的例外是当您想将 Exception 包装在您自己的自定义 Exception 中时。然后你应该这样做:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
Run Code Online (Sandbox Code Playgroud)
我没有看到有人提出的另一点:
如果您在catch {}块中什么也没做,那么try ... catch是没有意义的。我一直都这样看:
try
{
//Code here
}
catch
{
throw;
}
Run Code Online (Sandbox Code Playgroud)
或更糟的是:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
Run Code Online (Sandbox Code Playgroud)
最糟糕的是:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
189261 次 |
最近记录: |