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。