Posts tagged exception
Throw an Exception Which is NOT an Exception
Jun 21, 2006
在C#中,用什么语句可以捕获所有的异常?——对于这个问题,很多人可能很习惯地用写出下面的程序:
//Some code
}
catch (System.Exception ex) {
System.Console.Write("Error!");
}
这条语句的捕获对象是“System.Exception”。由于.Net中所有的异常必须直接或间接继承自这个类,因此理论上讲似乎是的确可以捕获所有异常的。但是仔细想想,真的没有办法抛出一个不是继承自System.Exception的对象吗?如果答案是可以的,那么显然这种异常就无法由上面的语句捕获。
抛出不是异常的异常……这种想起来都觉得不可能的事情,可能吗?事实上,关于这个问题.Net 1.x 和 2.0有一些细微差别,下面分开考虑。
■在.Net 1.x当中,抛出不继承自System.Exception的对象是可能的
例如,在C++当中,我们可以用throw "Error!"这样的语句,将一个字符串作为“异常”抛出;在IL当中,我们甚至可以用下面的方式,将任何对象作为异常抛出:
.method static public void Start( ) {
ldstr "Oops"
throw
ret
}
}
因此,在.Net 1.x当中,经常使用下面这种最保险的方式:
{
//Some code
}
catch(System.Exception ex)
{
System.Console.WriteLine("System.Exception error: " + ex.Message);
}
catch
{
System.Console.WriteLine("Non System.Exception based error.);
}
其中第二个catch的效果就是,拦截“不是Exception及其子类的异常”。
■在.Net 2.0中,默认所有异常都必须继承自System.Exception;亦可和1.x相同方式运作
在.Net2.0当中,为了确保跨语言的兼容性(在C#下无法throw一个字符串,在C++下则可以),CLR会自动将不是继承自System.Exception的异常包裹在RuntimeWrappedException对象中——例如,在C++中throw一个字符串,该字符串将被包裹起来,实际上抛出的则是一个RuntimeWrappedException。这样的结果就是,所有语言抛出的异常将都是System.Exception的子类了。
但是同时,为了保证和1.x版本的兼容性,.Net 2.0提供了RuntimeCompatibilityAttribute类,指定CLR不要对异常进行包装:
附:测试用程序
-
[assembly: System.Runtime.CompilerServices.RuntimeCompatibility(WrapNonExceptionThrows = false)]
-
-
namespace ThrowerExample
-
{
-
class ThrowerHarness
-
{
-
static void Main(string[] args)
-
{
-
try
-
{
-
Thrower.ThrowException();
-
}
-
catch (System.Exception ex)
-
{
-
System.Console.WriteLine("System.Exception error: " + ex.Message);
-
}
-
catch
-
{
-
System.Console.WriteLine("Non System.Exception based error.");
-
}
-
-
try
-
{
-
Thrower.ThrowString();
-
}
-
catch (System.Exception ex)
-
{
-
System.Console.WriteLine("System.Exception error: " + ex.Message);
-
}
-
catch
-
{
-
System.Console.WriteLine("Non System.Exception based error.");
-
}
-
}
-
}
-
}
执行结果是,第一个异常将被catch(System.Exception ex){}捕获;第二个异常由于不是System.Exception的子类,将落到catch{}中。
但是如果把第一行的属性去掉,编译时将出现下面的警告:
执行的话,两个异常都将被catch(System.Exception ex){}捕获,看消息可知第二个异常的类型为RuntimeWrappedException。