dan*_*die 414 .net c# exception-handling exception
有些帖子询问这两者之间的区别是什么.
(为什么我还要提这个...)
但我的问题是不同的,我称之为"抛出前"在另一个错误的神像处理方法.
public class Program {
public static void Main(string[] args) {
try {
// something
} catch (Exception ex) {
HandleException(ex);
}
}
private static void HandleException(Exception ex) {
if (ex is ThreadAbortException) {
// ignore then,
return;
}
if (ex is ArgumentOutOfRangeException) {
// Log then,
throw ex;
}
if (ex is InvalidOperationException) {
// Show message then,
throw ex;
}
// and so on.
}
}
Run Code Online (Sandbox Code Playgroud)
如果try & catch
用于Main
,那么我会throw;
用来重新抛出错误.但在上面简化的代码中,所有异常都会通过HandleException
在调用内部时调用throw ex;
效果是否相同?throw
HandleException
Mar*_*ell 651
是,有一点不同;
throw ex
重置堆栈跟踪(因此您的错误似乎来自HandleException
)throw
没有 - 原始罪犯将被保留.
static void Main(string[] args)
{
try
{
Method2();
}
catch (Exception ex)
{
Console.Write(ex.StackTrace.ToString());
Console.ReadKey();
}
}
private static void Method2()
{
try
{
Method1();
}
catch (Exception ex)
{
//throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main)
throw ex;
}
}
private static void Method1()
{
try
{
throw new Exception("Inside Method1");
}
catch (Exception)
{
throw;
}
}
Run Code Online (Sandbox Code Playgroud)Sha*_*ica 94
(我之前发过,@ Marc Gravell纠正了我)
以下是差异的演示:
static void Main(string[] args) {
try {
ThrowException1(); // line 19
} catch (Exception x) {
Console.WriteLine("Exception 1:");
Console.WriteLine(x.StackTrace);
}
try {
ThrowException2(); // line 25
} catch (Exception x) {
Console.WriteLine("Exception 2:");
Console.WriteLine(x.StackTrace);
}
}
private static void ThrowException1() {
try {
DivByZero(); // line 34
} catch {
throw; // line 36
}
}
private static void ThrowException2() {
try {
DivByZero(); // line 41
} catch (Exception ex) {
throw ex; // line 43
}
}
private static void DivByZero() {
int x = 0;
int y = 1 / x; // line 49
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
Exception 1:
at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19
Exception 2:
at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25
Run Code Online (Sandbox Code Playgroud)
您可以看到在异常1中,堆栈跟踪返回到DivByZero()
方法,而在异常2中则没有.
注意到,虽然,在显示的行数ThrowException1()
和ThrowException2()
是的行号throw
的语句,不调用的行号DivByZero()
,这可能是有道理的,现在想起来有点...
例外1:
at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)
Run Code Online (Sandbox Code Playgroud)
例外2:
at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)
Run Code Online (Sandbox Code Playgroud)
它是否仅在调试模式下维护原始stackTrace?
Jep*_*sen 39
其他答案完全正确,但我认为这个答案提供了一些额外的答案.
考虑这个例子:
using System;
static class Program {
static void Main() {
try {
ThrowTest();
} catch (Exception e) {
Console.WriteLine("Your stack trace:");
Console.WriteLine(e.StackTrace);
Console.WriteLine();
if (e.InnerException == null) {
Console.WriteLine("No inner exception.");
} else {
Console.WriteLine("Stack trace of your inner exception:");
Console.WriteLine(e.InnerException.StackTrace);
}
}
}
static void ThrowTest() {
decimal a = 1m;
decimal b = 0m;
try {
Mult(a, b); // line 34
Div(a, b); // line 35
Mult(b, a); // line 36
Div(b, a); // line 37
} catch (ArithmeticException arithExc) {
Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);
// uncomment EITHER
//throw arithExc;
// OR
//throw;
// OR
//throw new Exception("We handled and wrapped your exception", arithExc);
}
}
static void Mult(decimal x, decimal y) {
decimal.Multiply(x, y);
}
static void Div(decimal x, decimal y) {
decimal.Divide(x, y);
}
}
Run Code Online (Sandbox Code Playgroud)
如果取消注释该throw arithExc;
行,则输出为:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 44
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
Run Code Online (Sandbox Code Playgroud)
当然,您丢失了有关异常发生位置的信息.如果你使用这throw;
条线,这就是你得到的:
Handling a DivideByZeroException.
Your stack trace:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 46
at Program.Main() in c:\somepath\Program.cs:line 9
No inner exception.
Run Code Online (Sandbox Code Playgroud)
这样做要好得多,因为现在你看到它是Program.Div
导致你出问题的方法.但是仍然很难看出这个问题是来自该try
区块的第35行还是第37行.
如果您使用第三个替代方法,包装在外部异常中,则不会丢失任何信息:
Handling a DivideByZeroException.
Your stack trace:
at Program.ThrowTest() in c:\somepath\Program.cs:line 48
at Program.Main() in c:\somepath\Program.cs:line 9
Stack trace of your inner exception:
at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
at System.Decimal.Divide(Decimal d1, Decimal d2)
at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
at Program.ThrowTest() in c:\somepath\Program.cs:line 35
Run Code Online (Sandbox Code Playgroud)
特别是你可以看到第35行导致问题.但是,这需要人们搜索InnerException
,并且在简单的情况下使用内部异常感觉有点间接.
在这篇博文中,他们通过调用(通过反射)对象的internal
intance方法InternalPreserveStackTrace()
来保留行号(try块的行)Exception
.但是使用这样的反射并不好(.NET Framework可能会在internal
某天没有警告的情况下更改其成员).
Shi*_*ala 21
抛出保留堆栈跟踪。所以假设 Source1 抛出 Error1 ,它被 Source2 捕获并且 Source2 说 throw 那么 Source1 Error + Source2 Error 将在堆栈跟踪中可用。
抛出 ex不保留堆栈跟踪。所以 Source1 的所有错误都将被清除,只有 Source2 错误会发送到客户端。
有时只是阅读内容不清楚,建议观看此视频演示以获得更多清晰度,C# 中的 Throw 与 Throw ex。
不,这将导致异常具有不同的堆栈跟踪。只有throw
在catch
处理程序中使用没有任何异常的对象才会保持堆栈跟踪不变。
无论是否重新抛出异常,您可能希望从 HandleException 返回一个布尔值。
小智 6
让我们理解throw和throw ex之间的区别.我听说在很多.net采访中都会被问到这个常见问题.
为了概括这两个术语,throw和throw ex都用于了解异常发生的位置.抛出ex重写异常的堆栈跟踪,而不管实际抛出的位置.
让我们通过一个例子来理解.
让我们先了解一下.
static void Main(string[] args) {
try {
M1();
} catch (Exception ex) {
Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
Console.WriteLine(ex.StackTrace.ToString());
Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
Console.WriteLine(ex.TargetSite.ToString());
}
Console.ReadKey();
}
static void M1() {
try {
M2();
} catch (Exception ex) {
throw;
};
}
static void M2() {
throw new DivideByZeroException();
}
Run Code Online (Sandbox Code Playgroud)
以上输出如下.
显示实际抛出异常的完整层次结构和方法名称..它是M2 - > M2.以及行号
其次..让我们通过throw ex了解.只需在M2方法catch块中用throw ex替换throw.如下.
throw ex代码的输出如下.
您可以看到输出中的差异.stone ex忽略所有先前的层次结构,并使用行/方法重置堆栈跟踪,其中写入了throw ex.
Microsoft Docs 代表:
一旦抛出异常,它携带的部分信息就是堆栈跟踪。堆栈跟踪是方法调用层次结构的列表,从抛出异常的方法开始,到捕获异常的方法结束。如果通过在
throw
语句中指定异常来重新抛出异常,则堆栈跟踪将在当前方法处重新启动,并且抛出异常的原始方法与当前方法之间的方法调用列表将丢失。要保留异常的原始堆栈跟踪信息,请使用throw
不指定异常的语句。
来源:https : //docs.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca2200
归档时间: |
|
查看次数: |
181376 次 |
最近记录: |