【More Effective C#】掩藏在Nullable<T>后的秘密
2010-10-27 08:19
197 查看
对于可空类型,我们并不陌生.例如,当我们为我们的数据库生成一个实体时,例如LINQ2SQL,查看实体类中的字段,经常会发现.我们那些定义为可空的字段的类型后面都会多了个?,如int?string?char?,bool?等等.这就是今天的主角---可空类型.
这个扩展方法看起来不会出什么错.实际上.它也能很好的运行.并很大程度上会优化我们的代码.但实际上.它也可能引入一些你可能不能预料到的问题.
与NaN有区别的是.可空类型支持空值之间的等同性比较
涉及可空数值类型的操作与NaN数值的操作的行为完全相同.
Nullable<T>中提供了一个GetValueORDefault实现.可以获取相关可空类型的默认值.这样,我们必须频繁的调用GetValueORDefault,为了减轻我们的工作量与抱怨.减少我们砸键盘的次数.所以,C#中的??出现了.
这是一段序列化可空类型int的实现.生成的XML如下.
可以看到.类型是int,却没有内容.这样,我们很难看出这段代码其实是由int?类型序列化生成的.信息丢失了.并且在反序列化时,你将十分痛恨自己为什么要使用可空类型.
除了序列化操作会信息丢失,在类型转换时.也会发生信息的丢失.
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>后面的一些小秘密.可空类型,如一把双刃剑,只有在更好的理解了它的一些特性之后.你才能将其使用得更加的得心应手.发挥其最大的效应.反之,它将给你带来无穷无尽的懊恼很悔恨(不断的咒骂着..该死的可空类型,该死的可空类型.).所以,最小化可空类型的可见范围(避免使用)将让我们的类型更易于使用,且不容易被误用.写出更高质量的代码.相关文章推荐
- C# nullable<T> 用法小结
- System.Nullable<T> int? 数据库中的int类型可以为空 在C# 中 的处理
- Nullable Modifier--from <Essential c# 2.0>
- 理解null值和C#中可空类型(NullAble<T>)
- <<More Effective C++>>读书笔记6: 杂项
- &lt;More Effective C++&gt;笔记--其他杂项
- 深入理解 c# 第四章 使用Nullable<T>的各个成员
- <<More Effective C++>>读书笔记1: 基础议题
- &lt;More Effective C++&gt;笔记--技巧
- <<More Effective C++>>读书笔记2: 运算符
- &lt;More Effective C++&gt;笔记--异常
- 【基础语言学习】C#中的可空类型运算(Nullable<T>)------T?
- &lt;More Effective C++&gt;笔记--运算符
- &lt;More Effective C++&gt;笔记--基础
- <<More Effective C++>>读书笔记4: 效率
- <<More Effective C++>>读书笔记5: 技巧(1)
- List<> 转换为Dataset的C#代码实现 解决Nullable问题
- <<More Effective C++>>读书笔记5: 技巧(2)
- <More Effective C++>笔记--基础
- <<More Effective C++>>读书笔记3: 异常