2.1 如何针对不一样的异常进行捕捉?程序员
相信阅读本文的园友都已经养成了try-catch的习惯,但对于异常的捕捉和处理可能并不在乎。确实,直接捕捉全部异常的基 类:Exception 使得程序方便易懂,但有时这样的捕捉对于业务处理没有任何帮助,对于特殊异常应该采用特殊处理可以更好地引导规划程序流程。框架
下面的代码演示了一个对于不一样异常进行处理的示例:性能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
|
public
class
Program
{
public
static
void
Main(
string
[] args)
{
Program p =
new
Program();
p.RiskWork();
Console.ReadKey();
}
public
void
RiskWork()
{
try
{
// 一些可能会出现异常的代码
}
catch
(NullReferenceException ex)
{
HandleExpectedException(ex);
}
catch
(ArgumentException ex)
{
HandleExpectedException(ex);
}
catch
(FileNotFoundException ex)
{
HandlerError(ex);
}
catch
(Exception ex)
{
HandleCrash(ex);
}
}
// 这里处理预计可能会发生的,不属于错误范畴的异常
private
void
HandleExpectedException(Exception ex)
{
// 这里能够借助log4net写入日志
Console.WriteLine(ex.Message);
}
// 这里处理在系统出错时可能会发生的,比较严重的异常
private
void
HandlerError(Exception ex)
{
// 这里能够借助log4net写入日志
Console.WriteLine(ex.Message);
// 严重的异常须要抛到上层处理
throw
ex;
}
// 这里处理可能会致使系统崩溃时的异常
private
void
HandleCrash(Exception ex)
{
// 这里能够借助log4net写入日志
Console.WriteLine(ex.Message);
// 关闭当前程序
System.Threading.Thread.CurrentThread.Abort();
}
}
|
(1)如代码所示,针对特定的异常进行不一样的捕捉一般颇有意义,真正的系统每每要针对不一样异常进行复杂的处理。异常的分别处理是一种好的编码习惯, 这要求程序员在编写代码的时候充分估计到全部可能出现异常的状况,固然,不管考虑得如何周到,最后都须要对异常的基类Exception进行捕捉,这样才 能保证全部的异常都不会被随意地抛出。测试
(2)除此以外,除了在必要的时候写try-catch,不少园友更推荐使用框架层面提供的异常捕捉方案,以.NET为例:编码
2.2 如何使用Conditional特性?spa
你们都知道,一般在编译程序时能够选择Bebug版本仍是Release版本,编译器将会根据”调试“和”发布“两个不一样的出发点去编译程序。在 Debug版本中,全部Debug类的断言(Assert)语句都会获得保留,相反在Release版本中,则会被统统删除。这样的机制有助于咱们编写出 方便调试同时又不影响正式发布的程序代码。调试
But,单纯的诊断和断言可能并不能彻底知足测试的需求,有时可能会须要大批的代码和方法去支持调试和测试,这个时候就须要用到 Conditional特性。Conditional特性用于编写在某个特定版本中运行的方法,一般它编写一些在Debug版本中支持测试的方法。当版本 不匹配时,编译器会把Conditional特性的方法内容置为空。日志
下面的一段代码演示了Conditional特性的使用:code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
|
//含有两个成员,生日和身份证
//身份证的第6位到第14位必须是生日
//身份证必须是18位
public
class
People
{
private
DateTime _birthday;
private
String _id;
public
DateTime Birthday
{
set
{
_birthday = value;
if
(!Check())
throw
new
ArgumentException();
}
get
{
Debug();
return
_birthday;
}
}
public
String ID
{
set
{
_id = value;
if
(!Check())
throw
new
ArgumentException();
}
get
{
Debug();
return
_id;
}
}
public
People(String id, DateTime birthday)
{
_id = id;
_birthday = birthday;
Check();
Debug();
Console.WriteLine(
"People实例被构造了..."
);
}
// 只但愿在DEBUG版本中出现
[Conditional(
"DEBUG"
)]
protected
void
Debug()
{
Console.WriteLine(_birthday.ToString(
"yyyy-MM-dd"
));
Console.WriteLine(_id);
}
//检查是否符合业务逻辑
//在全部版本中都须要
protected
bool
Check()
{
if
(_id.Length != 18 ||
_id.Substring(6, 8) != _birthday.ToString(
"yyyyMMdd"
))
return
false
;
return
true
;
}
}
public
class
Program
{
public
static
void
Main(
string
[] args)
{
try
{
People p =
new
People(
"513001198811290215"
,
new
DateTime(1988, 11, 29));
p.ID =
"513001198811290215"
;
}
catch
(ArgumentException ex)
{
Console.WriteLine(ex.GetType().ToString());
}
Console.ReadKey();
}
}
|
下图则展现了上述代码在Debug版本和Release版本中的输出结果:orm
①Debug版本:
②Release版本:
Conditional机制很简单,在编译的时候编译器会查看编译状态和Conditional特性的参数,若是二者匹配,则正常编译。不然,编译器将简单地移除方法内的全部内容。
2.3 如何避免类型转换时的异常?
咱们常常会面临一些类型转换的工做,其中有些是肯定能够转换的(好比将一个子类类型转为父类类型),而有些则是尝试性的(好比将基类引用的对象转换成子类)。当执行常识性转换时,咱们就应该作好捕捉异常的准备。
当一个不正确的类型转换发生时,会产生InvalidCastException异常,有时咱们会用try-catch块作一些尝试性的类型转换, 这样的代码没有任何错误,可是性能却至关糟糕,为何呢?异常是一种耗费资源的机制,每当异常被抛出时,异常堆栈将会被创建,异常信息将被加载,而一般这 些工做的成本相对较高,而且在尝试性类型转换时,这些信息都没有意义。
So,在.NET中提供了另一种语法来进行尝试性的类型转换,那就是关键字 is 和 as 所作的工做。
(1)is 只负责检查类型的兼容性,并返回结果:true 和 false。→ 进行类型判断
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public
static
void
Main(
string
[] args)
{
object
o =
new
object
();
// 执行类型兼容性检查
if
(o
is
ISample)
{
// 执行类型转换
ISample sample = (ISample)o;
sample.SampleShow();
}
Console.ReadKey();
}
|
(2)as 不只负责检查兼容性还会进行类型转换,并返回结果,若是不兼容则返回 null 。→ 用于类型转型
1
2
3
4
5
6
7
8
9
10
11
12
|
public
static
void
Main(
string
[] args)
{
object
o =
new
object
();
// 执行类型兼容性检查
ISample sample = o
as
ISample;
if
(sample !=
null
)
{
sample.SampleShow();
}
Console.ReadKey();
}
|
二者的共同之处都在于:不会抛出异常!综上比较,as 较 is 在执行效率上会好一些,在实际开发中应该量才而用,在只进行类型判断的应用场景时,应该多使用 is 而不是 as。