C# 抛出和抛出新异常()之间的差异
两者的区别是什么C# 抛出和抛出新异常()之间的差异,c#,C#,两者的区别是什么 try { ... } catch{ throw } 及 不管第二个是否显示消息?抛出重新引用原始异常并保留其原始堆栈跟踪 throw-ex抛出原始异常,但重置堆栈跟踪,销毁所有堆栈跟踪信息,直到catch块 永远不要写throw-ex 抛出新异常(例如消息)更糟糕。它创建一个全新的异常实例,丢失异常的原始堆栈跟踪及其类型。(例如,IOException)。 此外,某些异常包含附加信息(例如,ArgumentException.ParamName)。 抛出新异常(例如消
try { ... }
catch{ throw }
及
不管第二个是否显示消息?
抛出代码>重新引用原始异常并保留其原始堆栈跟踪
throw-ex
抛出原始异常,但重置堆栈跟踪,销毁所有堆栈跟踪信息,直到catch
块
永远不要写throw-ex代码>
抛出新异常(例如消息)代码>更糟糕。它创建一个全新的异常
实例,丢失异常的原始堆栈跟踪及其类型。(例如,IOException
)。
此外,某些异常包含附加信息(例如,ArgumentException.ParamName
)。
抛出新异常(例如消息)代码>也将销毁此信息
在某些情况下,您可能希望将所有异常包装在自定义异常对象中,以便提供有关抛出异常时代码所做操作的附加信息
为此,定义一个继承Exception
、的新类,以及一个可选的附加构造函数,该构造函数接受InnerException
以及附加信息,并抛出新的异常类,将ex
作为InnerException
参数传递。通过传递原始InnerException
,可以保留原始异常的所有属性,包括堆栈跟踪。throw
重新抛出捕获的异常,保留堆栈跟踪,而throw new exception
会丢失捕获的异常的一些详细信息
您通常会单独使用throw
来记录异常,而不会在此时完全处理它
BlackWasp有一篇标题足够好的文章。throw
用于重新引发捕获的异常。如果您想在将异常传递到调用链之前处理它,这将非常有用
使用不带任何参数的throw
会保留调用堆栈以进行调试。抛出新异常会吹走当前堆栈跟踪
抛出
将保留原始堆栈跟踪,并且几乎总是更有用。该规则的例外情况是,您希望将该例外情况包装到自己的自定义例外情况中。然后你应该做:
catch(Exception e)
{
throw new CustomException(customMessage, e);
}
如果需要,可以抛出新异常,将原始异常设置为内部异常。第一个异常保留原始堆栈跟踪:
try { ... }
catch
{
// Do something.
throw;
}
第二个选项允许您更改异常和/或消息和其他数据的类型:
try { ... } catch (Exception e)
{
throw new BarException("Something broke!");
}
还有第三种方法可以传递内部异常:
try { ... }
catch (FooException e) {
throw new BarException("foo", e);
}
我建议使用:
- 如果您希望在错误情况下执行一些清理,而不销毁信息或添加有关错误的信息,则第一种方法是
- 如果要添加有关错误的更多信息,请单击第三个按钮
- 如果要隐藏信息(对不受信任的用户),则第二个选项
第二个示例将重置异常的堆栈跟踪。第一种方法最准确地保留了异常的起源。此外,您还打开了原始类型的包装,这是了解实际错误的关键。。。如果功能需要第二个,例如添加扩展信息或使用特殊类型(如自定义“HandleableException”)重新包装,则只需确保也设置了InnerException属性 最重要的区别是第二个表达式删除了异常类型。异常类型在捕获异常时起着至关重要的作用:
public void MyMethod ()
{
// both can throw IOException
try { foo(); } catch { throw; }
try { bar(); } catch(E) {throw new Exception(E.message); }
}
(...)
try {
MyMethod ();
} catch (IOException ex) {
Console.WriteLine ("Error with I/O"); // [1]
} catch (Exception ex) {
Console.WriteLine ("Other error"); // [2]
}
如果foo()
抛出IOException
,[1]
catch块将捕获异常。但是当bar()
抛出IOException
时,它将被转换为普通的异常
ant不会被[1]
捕获块捕获。我没有看到任何人提出的另一点:
如果在catch{}块中没有执行任何操作,那么尝试一下……catch是没有意义的。我一直看到这一点:
try
{
//Code here
}
catch
{
throw;
}
或者更糟:
try
{
//Code here
}
catch(Exception ex)
{
throw ex;
}
最糟糕的是:
try
{
//Code here
}
catch(Exception ex)
{
throw new System.Exception(ex.Message);
}
throw或throw ex都用于抛出或重新抛出异常,当您只需记录错误信息而不想将任何信息发送回调用方时,只需将错误记录在catch中并离开即可。但是,如果您想向使用throw或throw-ex的调用方发送有关异常的一些有意义的信息,那么throw和throw-ex之间的区别在于throw保留堆栈跟踪和其他信息,但throw-ex创建了一个新的异常对象,因此原始堆栈跟踪丢失。
因此,我们应该在什么时候使用throw和throw e,在一些情况下,您可能希望重新抛出异常,比如重置调用堆栈信息。例如,如果方法位于库中,并且您希望对调用代码隐藏库的详细信息,则不一定希望调用堆栈包含库中私有方法的信息。在这种情况下,您可以捕获库的公共方法中的异常,然后重新引用它们,以便调用堆栈从这些公共方法开始 投掷;重新显示原始异常并保留异常类型
抛出新异常();重新显示原始异常类型并重置异常堆栈跟踪
掷骰子;重置异常堆栈跟踪并重置异常类型此处的答案均未显示差异,这可能有助于努力理解差异的人们。考虑这个示例代码:
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());
}
}
}
}
}
使用系统;
使用System.Collections.Generic;
名称空间异常
{
班级计划
{
静态void Main(字符串[]参数)
{
无效失败()
{
(作为字符串为null);
}
无效光掷()
{
尝试
{
失败();
}
捕获(例外)
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());
}
}
}
}
}
Bare Throw:
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__bareThrow|0_1() in C:\...\ExceptionDemo\Program.cs:line 19
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Rethrow
----------------------------------------
System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<>c.<Main>g__rethrow|0_2() in C:\...\ExceptionDemo\Program.cs:line 35
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64
Inner Throw
----------------------------------------
System.Exception: outer ---> System.NullReferenceException: Object reference not set to an instance of an object.
at ExceptionDemo.Program.<Main>g__fail|0_0() in C:\...\ExceptionDemo\Program.cs:line 12
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 43
--- End of inner exception stack trace ---
at ExceptionDemo.Program.<>c.<Main>g__innerThrow|0_3() in C:\...\ExceptionDemo\Program.cs:line 47
at ExceptionDemo.Program.Main(String[] args) in C:\...\ExceptionDemo\Program.cs:line 64