【More Effective C#】掩藏在Nullable<T>后的秘密
2010-10-27 08:19 空逸云 閱讀(2135) 評論(21) 收藏 舉報對于可空類型,我們并不陌生.例如,當我們為我們的數據庫生成一個實體時,例如LINQ2SQL,查看實體類中的字段,經常會發現.我們那些定義為可空的字段的類型后面都會多了個?,如int?string?char?,bool?等等.這就是今天的主角---可空類型.
Nullable<T>
事實上,所有的可空類型都繼承自Nullable<T>類,而編譯器為了方便大眾,提供了幾個常用的可空類型,可空基本類型.可空類型,顧名思義,它是可空的.這意味著,與非可空類型相比.可空類型需要更多的檢查.可空類型為非可空類型添加了一種丟失或不可用的狀態.日常項目中.可空類型似乎可以為我們帶來很多的好處.
public static int? DefaultParse(this string input) { int answer; return int.TryParse(input, out answer) ? answer : default(int?); }
這個擴展方法看起來不會出什么錯.實際上.它也能很好的運行.并很大程度上會優化我們的代碼.但實際上.它也可能引入一些你可能不能預料到的問題.
Nullable<T>的運算
可空數值類型提供了類似浮點數和NaN之間的語義,所有涉及NaN的比較都將返回false.
double d = 0; Console.WriteLine(d > double.NaN); //false Console.WriteLine(d < double.NaN); //false Console.WriteLine(double.NaN > double.NaN); //false Console.WriteLine(double.NaN == double.NaN); //false
與NaN有區別的是.可空類型支持空值之間的等同性比較
int? nullableOne = default(int?); int? nullableTwo = 0; int? nullableThree = default(int?); Console.WriteLine(nullableOne < nullableTwo); //false Console.WriteLine(nullableOne > nullableTwo); //false Console.WriteLine(nullableOne == nullableThree); //true
涉及可空數值類型的操作與NaN數值的操作的行為完全相同.
double d = 0; Console.WriteLine(d + double.NaN); //NaN Console.WriteLine(d - double.NaN); //NaN Console.WriteLine(d * double.NaN); //NaN Console.WriteLine(d / double.NaN); //NaN int? nullableOne = default(int?); int? nullableTwo = default(int); Console.WriteLine((nullableOne + nullableTwo).HasValue); //false //....
Nullable<T>中提供了一個GetValueORDefault實現.可以獲取相關可空類型的默認值.這樣,我們必須頻繁的調用GetValueORDefault,為了減輕我們的工作量與抱怨.減少我們砸鍵盤的次數.所以,C#中的??出現了.
??操作符
??操作符,也叫空值合并運算符.它是一個二元運算符.左邊為可空類型,判讀左邊的值是否為空,若為空,則返回右邊的值,否則返回左邊的值.例如
int? result = 123; return result ?? 321; //return 123; int? result = default(int?); return result ?? 321; //return 321;
Nullable<T>信息丟失
在很多情況下.我們很Happy的使用著可空類型.但很多時候并難以理清某些特別情況下可空類型返回的結果.
int? f = default(int?); XmlSerializer x = new XmlSerializer(typeof(int?)); StringWriter t = new StringWriter(); x.Serialize(t, f);
這是一段序列化可空類型int的實現.生成的XML如下.
可以看到.類型是int,卻沒有內容.這樣,我們很難看出這段代碼其實是由int?類型序列化生成的.信息丟失了.并且在反序列化時,你將十分痛恨自己為什么要使用可空類型.
string storage = t.ToString(); StringReader s = new StringReader(storage); var f2 = (int)x.Deserialize(s); //f2不能為空 Console.WriteLine(f2);
除了序列化操作會信息丟失,在類型轉換時.也會發生信息的丟失.
int? defaultNullable = default(int?); string s = defaultNullable.ToString(); //轉換成string的空內容""或string.Empty Console.Write(s); string s2 = ((object)defaultNullable).ToString(); //裝箱后為null,ToString操作不能為空出錯 Console.Write(s2);
最小化可空類型的可見范圍
經過以上的"血淚史".我們終于可以看清Nullable<T>后面的一些小秘密.可空類型,如一把雙刃劍,只有在更好的理解了它的一些特性之后.你才能將其使用得更加的得心應手.發揮其最大的效應.反之,它將給你帶來無窮無盡的懊惱很悔恨(不斷的咒罵著..該死的可空類型,該死的可空類型.).所以,最小化可空類型的可見范圍(避免使用)將讓我們的類型更易于使用,且不容易被誤用.寫出更高質量的代碼.
出處:http://kongyiyun.cnblogs.com
本文版權歸作者和博客園共有,歡迎轉載,但未經作者同意必須保留此段聲明,且在文章頁面明顯位置給出原文連接,否則保留追究法律責任的權利。
浙公網安備 33010602011771號