可空类型NullableT刘家芳芳到底是什么鬼鬼

C#可空类型_Linux编程_Linux公社-Linux系统门户网站
你好,游客
C#可空类型
来源:Linux社区&
作者:wilber2013
在程序开发中,有时候需要值类型也为可空类型,比如,在数据库中,我们可以把一个日期Datetime设置为null。
在C# 2.0中就出现了可空类型,允许值类型也可以为空(null),可空类型的实现基于C#泛型。
可空类型基本知识
可空类型的核心是System.Nullable&T&,同时静态类System.Nullable为可空类型提供了很多实用的方法。下面分别看看可空类型的这两个重要组成部分。
System.Nullable&T&
通过ILSpy我们可以查看这个类型的C#代码:
从上面的图中可以看到关于System.Nullable&T&的一些关键点:
Nullable&T&是一个泛型类型
类型参数T有一个值类型的约束(根据值类型约束T : struct,T不能为可空类型,也就是说Nullable&Nullable&int&&是不允许的)
Nullable&T&是一个值类型(是一个struct)
对于任何具体的可空类型来说,T的类型为可空类型的基础类型(underlying type),例如Nullable&int&的基础类型就是int。
通过上面代码还可以看到,Nullable&T&有两个重要的属性,HasValue和Value。通过它们可以了解可空类型是怎么工作的:
如果一个可空值类型存在一个真正的值,那么Value就代表这个值本身,同时HasValue值为true
如果一个可空值类型为空,那么HasValue为false,Value这是没有意义。
下面看一个可空类型的简单例子,进一步了解一下可空类型:
static void Display(Nullable&int& x)
Console.WriteLine("HasValue: {0}", x.HasValue);
if (x.HasValue)
Console.WriteLine("Value: {0}", x.Value);
Console.WriteLine("Explicit conversion: {0}", (int)x);
Console.WriteLine("GetValueOrDefault(): {0}", x.GetValueOrDefault());
Console.WriteLine("GetValueOrDefault(10): {0}", x.GetValueOrDefault(10));
Console.WriteLine("ToString(): {0}", x.ToString());
Console.WriteLine("GetHashCode(): {0}", x.GetHashCode());
Console.WriteLine();
static void Main(string[] args)
Nullable&int& x = 5;
Display(x);
x = new Nullable&int&(9);
Display(x);
x = new Nullable&int&();
Display(x);
Console.Read();
程序的输出为:
通过这段代码可以看到HasValue和Value的使用,以及Nullable&T&中一些常用的方法。
注意,在这段代码中,下面两句的IL代码是一样的:
Nullable&int& x = 5;
x = new Nullable&int&(9);
IL_0004: call instance void valuetype [mscorlib]System.Nullable`1&int32&::.ctor(!0)
IL_0015: call instance void valuetype [mscorlib]System.Nullable`1&int32&::.ctor(!0)
这里涉及了包装(wrapping)和拆包(unwrapping)的概念:将T的一个实例转换成Nullable&T&的一个实例的过程在C#中成为包装,相反的过程成为拆包。这个概念跟装箱和拆箱不一样,后面会看到Nullable&T&的装箱和拆箱。
Nullable&T&的装箱和拆箱
从前面的分析可以看到Nullable&T&是一个结构,也就是一个值类型。也就是说,当我们把可空类型转换成一个引用类型的时候需要进行装箱操作。
对于Nullable&T&的装箱和拆箱可以概括为:
Nullable&T&的实例要么装箱为空引用,要么装箱成T的一个以装箱的值
已装箱的值可以拆箱成普通类型,或者拆箱为对于的可空类型
拆箱一个空引用时,如果拆箱为普通类型,会抛出一个NullReferenceException的异常
如果拆箱成恰当的可控类型,就会拆箱成一个没有值的Nullable&T&实例
看一个关于可空类型装箱和拆箱的例子:
static void Main(string[] args)
Nullable&int& x = 5;
//有值的可空类型装箱
object boxed =
Console.WriteLine(x.GetType());
//拆箱为普通类型
int normal = (int)
Console.WriteLine(normal);
//拆箱为可空类型
x = (Nullable&int&)
Console.WriteLine(x);
x = new Nullable&int&();
//空的可空类型装箱
Console.WriteLine(boxed == null);
//拆箱为可空类型
x = (Nullable&int&)
Console.WriteLine(x.HasValue);
System.Nullable
System.Nullable是一个静态类,只包含三个静态方法,大家可以通过ILSpy进行查看,这里就不上图了。
下面两个方法是比较方法:
public static int Compare&T&(T? n1, T? n2) where T : struct
public static bool Equals&T&(T? n1, T? n2) where T : struct
下面这个方法用来获得可空类型的基础类型:
public static Type GetUnderlyingType(Type nullableType)
可空类型语法糖
在C# 2.0中,我们可以使用?修饰符来表示可空类型。
下面的C#语句具有相同的IL代码。
Nullable&int& x = 5;
int? y = 5;
IL_0004: call instance void valuetype [mscorlib]System.Nullable`1&int32&::.ctor(!0)
IL_000d: call instance void valuetype [mscorlib]System.Nullable`1&int32&::.ctor(!0)
使用null进行赋值和比较
C#编译器允许使用null在比较和赋值中表示一个可空类型的空值。
对于下面的代码,通过IL可以发现"x == null"实际调用的是HasValue属性进行比较。
int? x = null;
Console.WriteLine(x == null);
IL_000b: call instance bool valuetype [mscorlib]System.Nullable`1&int32&::get_HasValue()
C# 2.0中出现的可空类型解决了我们很多的问题,可空类型的相关知识还是比较容易理解的。
在使用中,我们可以直接使用?修饰符来创建可空值类型。
C#委托的基本概念
进一步理解C#委托
C#多线程编程实例 线程与窗体交互【附源码】
C#数学运算表达式解释器
在C语言中解析JSON配置文件
C++ Primer Plus 第6版 中文版 清晰有书签PDF+源代码
本文永久更新链接地址:
相关资讯 & & &
& (08月30日)
& (04月01日)
& (04月21日)
& (03月10日)
   同意评论声明
   发表
尊重网上道德,遵守中华人民共和国的各项有关法律法规
承担一切因您的行为而直接或间接导致的民事或刑事法律责任
本站管理人员有权保留或删除其管辖留言中的任意内容
本站有权在网站内转载或引用您的评论
参与本评论即表明您已经阅读并接受上述条款&&& 可空类型Nullable&T&是.NET Framework 2.0中新增的类型,用它声明的值类型,除了存值之外,还可以表示为null,即该类型的变量可以为空。
&&& 下面是Nullable结构的定义:
&1namespace&System
&3&&&&[Serializable]
&4&&&&public&struct&Nullable&T&&where&T&:&struct
&6&&&&&&&&public&Nullable(&T&value&);
&8&&&&&&&&public&static&explicit&operator&T(&T?&value&);
&9&&&&&&&&public&static&implicit&operator&T?(&T&value&);
11&&&&&&&&public&bool&HasValue&{&get;&}
13&&&&&&&&public&T&Value&{&get;&}
15&&&&&&&&public&override&bool&Equals(&object&other&);
16&&&&&&&&
17&&&&&&&&public&override&int&GetHashCode();
18&&&&&&&&
19&&&&&&&&public&T&GetValueOrDefault();
20&&&&&&&&
21&&&&&&&&public&T&GetValueOrDefault(&T&defaultValue&);
22&&&&&&&&
23&&&&&&&&public&override&string&ToString();
&&& 从定义可以看出,Nullable&T&结构中的类型参数T必须是一个结构,这就意味着Nullable&T&只支持将值类型用作可空类型,因为引用类型本身就是可空的。另外还可以看出,将值类型(如int)可以隐式地转换为可空类型,而可空类型转换为值类型则要进行显式转换。Nullable&T&还有两个重要的属性:HasValue和Value,前者判断变量内是值还是null,并返回一个布尔值,后者用于取出相应类型的值。很明显如何可空类型的变量此时保存的是null,那么使用Value属性会产生异常(InvalidOperationException)。
&&& 使用Nullable&T&声明一个存储int值的可空类型变量,可以这样写:
1Nullable&int&&a&=&null;
&&& 这样变量a既可以存储整型值,也可以存储null了。在C#中还有简化的写法:
int?&a&=&null;
&&& 这样用起来更加方便。
&&& 有了可空类型,那么在从数据库中取值时,如果碰到了NULL值,语句能简化一些,例如,如果不使用可空类型,那么语句可能会这样写:
1if&(dataReader["SSN"]&==&DBNull.Value)
2&&& ssn&=&-1;&// NULL&用&-1&代替
4&&& ssn&=&Convert.ToInt64(dataReader["SSN"]);
&&& 因为传统的值类型不能为null,所以必须为数据库中的NULL值提供一个无效的值,有时候这个无效的值并不好找。而使用可空类型,变量可以为null,那么我们就可以这样写:
1ssn&=&dataReader["SSN"]&==&DBNull.Value&?&(long?)null&:&Convert.ToInt64(dataReader["SSN"]);
&&& 在访问可空类型变量中的值时,最好先检查一下HasValue属性,判断一下是否有值,以避免异常发生,例如:
1if&(ssn.HasValue)
3&&& long&ssn&=&(long)&//&或&ssn.Value
4&&& Console.WriteLine("SSN&=&{0}",&ssn);
&&& 总之,适当地使用可空类型,能够简化代码,减少一些麻烦。
&&& 参考文档:
阅读(...) 评论()1304人阅读
1 可空类型的声明
public struct Nullable&T& where T: struct
T为结构体,所以只有值类型才可以使用Nullable&T&声明为“可空类型”。
2 可空类型的作用
可空类型在基元类型正常值范围外加上了空值null。
使用可空类型,接收数据库的可空字段值时更加方便。
3 可空类型与基元类型的转换
基元类型可以隐式转换为其对应的可空类型。
可空类型不可以隐式转换为对应的基元类型。
Nullable&int& a =// 可空类型,包含空值null
int b = 1;//基元类型
a =//转换成功
b =//转换失败
T?是Nullable&T&的简写,两者可互换。&
int b = a ?? 1;
if (a.HasValue)
如果a.HasValue为true,则将a.HasValue赋值给b,否则将1赋值给b。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:494989次
积分:7483
积分:7483
排名:第2155名
原创:251篇
转载:37篇
评论:75条
(5)(22)(2)(27)(4)(3)(1)(10)(2)(10)(10)(8)(1)(1)(1)(2)(14)(10)(4)(3)(4)(10)(16)(5)(6)(19)(24)(22)(17)(16)(1)(3)(1)(1)(3)可空类型_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
上传于||文档简介
&&可​空​类​型
阅读已结束,如果下载本文需要使用1下载券
想免费下载本文?
定制HR最喜欢的简历
你可能喜欢可空类型Nullable到底是什么鬼
可空类型Nullable到底是什么鬼
原文出处: &&&值类型为什么不可以为空首先我们都知道引用类型默认值都是null,而值类型的默认值都有非null。为什么引用类型可以为空?因为引用类型变量都是保存一个对象的地址引用(就像一个url对应一个页面),而引用类型值为null的时候是变量值指向了一个空引用(如同一个空的url)那为什么值不能有空值呢?其实很简单,因为如int值范围是-到。其中根本就没有给null值留那么一个位置。我们为什么需要用到可空类型举个栗子吧,我们定义一个人(Person),它有三个属性出生日期(BeginTime)、死亡日期(EndTime)、年龄(Age)。如果这个人还健在人世,请问怎么给死亡日期赋值?有人很聪明说“为空啊”。是的,这就是我们的需求。微软在C#2.0的时候就为我们引入了可null值类型(&System.Nullable&),那么下面来定义Person类。
12345678910111213141516171819202122232425
public class Person{&&&&/// &&&&/// 出生日期&&&&/// &&&&public DateTime BeginTime { get; set; }&&&&/// &&&&/// 死亡日期&&&&/// &&&&public System.NullableDateTime> EndTiem { get; set; }&&&&public int Age&&&&{&&&&&&&&get&&&&&&&&{&&&&&&&&&&&&if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&return (EndTiem.Value - BeginTime).Days;&&&&&&&&&&&&}&&&&&&&&&&&&else//还没挂&&&&&&&&&&&&{&&&&&&&&&&&&&&&&return (DateTime.Now - BeginTime).Days;&&&&&&&&&&&&}&&&&&&&&}&&&&}}
这样,我们就可以很容易获得一个人的年龄了。
123456789101112131415161718
static void Main(string[] args){&&&&Person p1 = new Person()&&&&{&&&&&&&&BeginTime = DateTime.Parse('')&&&&};&&&&Person p2 = new Person()&&&&{&&&&&&&&BeginTime = DateTime.Parse(''),&&&&&&&&EndTiem = DateTime.Parse('')&&&&};&&&&Console.WriteLine('我今年' + p1.Age + '岁。');&&&&Console.WriteLine('毛爷爷活了' + p2.Age + '岁。');&&&&Console.ReadKey();}
可空类型的实现我们前面用到了&System.Nullable&来表示可空时间类型,其实平时我们用得更多的是&DateTime?&直接在类型T后面加一个问号,这两种是等效的。多亏了微软的语法糖。我们来看看&System.Nullable&到底是何物。搜噶,原来是一个结构。还看到了我们属性的 HasValue和Value属性。原来竟这般简单。一个结构两个属性,一个存值,一个存是否有值。那么下面我们也来试试吧。不好意思,让大家失望了。前面我们就说过了,值类型是不可以赋值null的(结构也是值类型)。怎么办!怎么办!不对啊,微软自己也是定义的结构,它怎么可以直接赋值null呢。(奇怪,奇怪,毕竟是人家微软自己搞得,可能得到了特殊的待遇吧)可是,这样就让我们止步了吗?NO!我们都知道,看微软的IL(中间语言)的时候,就像脱了它的衣服一样,很多时候不明白的地方都可以看个究竟,下面我们就去脱衣服。首先,我们用几种不同的方式给可空类型赋值。
12345678910111213
static void Main(string[] args){&&&&System.Nullableint> number1 = null;&&&&System.Nullableint> number2 = new System.Nullableint>();&&&&System.Nullableint> number3 = 23;&&&&System.Nullableint> number4 = new System.Nullableint>(88);&&&&Console.ReadKey();}
然后用reflector看编译后的IL。原来如此,可空类型的赋值直接等效于构造实例。赋null时其实就是调用空构造函数,有值时就就把值传入带参数的构造函数。(柳暗花明又一村。如此,我们是否可以接着上面截图中的&MyNullable&继续模拟可空类型呢?且继续往下看。)
12345678910111213141516171819202122232425262728293031323334
public struct MyNullablewhere T : struct{&&&&//错误&&&&1&&&&结构不能包含显式的无参数构造函数 &&&&//还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响&&&&//public MyNullable()&&&&//{&&&&//&&&&this._hasValue =&&&&//}&&&&public MyNullable(T value)//有参构造函数&&&&{&&&&&&&&this._hasValue = true;&&&&&&&&this._value = value;&&&&}&&&&private bool _hasValue;&&&&public bool HasValue//是否不为空&&&&{&&&&&&&&get { return _hasValue; }&&&&}&&&&private T _value;&&&&public T Value//值&&&&{&&&&&&&&get&&&&&&&&{&&&&&&&&&&&&if (!this._hasValue)//如没有值,还访问就抛出异常&&&&&&&&&&&&{&&&&&&&&&&&&&&&&throw new Exception(' 可为空的对象必须具有一个值');&&&&&&&&&&&&}&&&&&&&&&&&&return _value;&&&&&&&&}&&&&}}
哟西,基本上已经模拟出了可空类型出来的。(但是我们还是不能直接赋值,只能通过构造函数的方式来使用自定义的可空类型)。全部代码如下:
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace 可空类型{&&&&public class Person&&&&{&&&&&&&&/// &&&&&&&&/// 出生日期&&&&&&&&/// &&&&&&&&public DateTime BeginTime { get; set; }&&&&&&&&/// &&&&&&&&/// 死亡日期&&&&&&&&/// &&&&&&&&public MyNullable EndTiem { get; set; } //这里改用MyNullable&&&&&&&&/// &&&&&&&&/// 年龄&&&&&&&&/// &&&&&&&&public double Age&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (EndTiem.Value - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&else//还没挂&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (DateTime.Now - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&public struct MyNullablewhere T : struct&&&&{&&&&&&&&//错误&&&&1&&&&结构不能包含显式的无参数构造函数 &&&&&&&&//还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响&&&&&&&&//public MyNullable()&&&&&&&&//{&&&&&&&&//&&&&this._hasValue =&&&&&&&&//}&&&&&&&&public MyNullable(T value)//有参构造函数&&&&&&&&{&&&&&&&&&&&&this._hasValue = true;&&&&&&&&&&&&this._value = value;&&&&&&&&}&&&&&&&&private bool _hasValue;&&&&&&&&public bool HasValue//是否不为空&&&&&&&&{&&&&&&&&&&&&get { return _hasValue; }&&&&&&&&}&&&&&&&&private T _value;&&&&&&&&public T Value//值&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (!this._hasValue)//如没有值,还访问就抛出异常&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&throw new Exception(' 可为空的对象必须具有一个值');&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&return _value;&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&class Program&&&&{&&&&&&&&static void Main(string[] args)&&&&&&&&{&&&&&&&&&&&&Person p1 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse('')&&&&&&&&&&&&};&&&&&&&&&&&&Person p2 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse(''),&&&&&&&&&&&&&&&&EndTiem = new MyNullable(DateTime.Parse(''))//这里使用MyNullable的有参构造函数&&&&&&&&&&&&};&&&&&&&&&&&&Console.WriteLine('我今年' + p1.Age + '岁。');&&&&&&&&&&&&Console.WriteLine('毛爷爷活了' + p2.Age + '岁。');&&&&&&&&&&&&Console.ReadKey();&&&&&&&&}&&&&}}
和系统的可空类型得出了相同的结果。总结可空类型是结构(也就是值类型)所以可空类型的null值和引用类型的null是不一样的。(可空类型的并不是引用类型的null,而是用结构的另一种表示方式来表示null)有同学问,怎么样才可以做到直接赋值呢?这个我也没有什么好的办法,或许需要编译器的支持。以上内容都是胡说八道。希望能对您有那么一点点用处,感谢阅读。============== 更新==============上面我们提出了疑问“怎么样才可以做到直接赋值呢”,本来我是没有好的解决办法。这里要感谢我们的园友@冲杀给我提供了好的解决方案。implicit(关键字用于声明隐式的用户定义类型转换运算符。)
public static implicit operator MyNullable(T value){&&&&&& return new MyNullable(value);}
只需要在&struct MyNullable&中添加以上代码,就可以直接赋值了。(作用等效于是直接重写了“=”赋值符号)完整代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace test{&&&&public class Person&&&&{&&&&&&&&/// &&&&&&&&/// 出生日期&&&&&&&&/// &&&&&&&&public DateTime BeginTime { get; set; }&&&&&&&&/// &&&&&&&&/// 死亡日期&&&&&&&&/// &&&&&&&&public MyNullable EndTiem { get; set; } //这里改用MyNullable&&&&&&&&/// &&&&&&&&/// 年龄&&&&&&&&/// &&&&&&&&public double Age&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (EndTiem.Value - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&else//还没挂&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (DateTime.Now - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&public struct MyNullablewhere T : struct&&&&{&&&&&&&&//错误&&&&1&&&&结构不能包含显式的无参数构造函数 &&&&&&&&//还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响&&&&&&&&//public MyNullable()&&&&&&&&//{&&&&&&&&//&&&&this._hasValue =&&&&&&&&//} &&&&&&&&public MyNullable(T value)//有参构造函数&&&&&&&&{&&&&&&&&&&&&this._hasValue = true;&&&&&&&&&&&&this._value = value;&&&&&&&&}&&&&&&&&private bool _hasValue;&&&&&&&&public bool HasValue//是否不为空&&&&&&&&{&&&&&&&&&&&&get { return _hasValue; }&&&&&&&&}&&&&&&&&private T _value;&&&&&&&&public T Value//值&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (!this._hasValue)//如没有值,还访问就抛出异常&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&throw new InvalidOperationException(' 可为空的对象必须具有一个值');&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&return _value;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&public static implicit operator MyNullable(T value)&&&&&&&&{&&&&&&&&&&&&return new MyNullable(value);&&&&&&&&} &&&&}&&&&class Program&&&&{&&&&&&&&static void Main(string[] args)&&&&&&&&{&&&&&&&&&&&&Person p1 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse('')&&&&&&&&&&&&};&&&&&&&&&&&&Person p2 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse(''),&&&&&&&&&&&&&&&&EndTiem = DateTime.Parse('') &&&&&&&&&&&&&&&&//new MyNullable(DateTime.Parse(''))&&&&&&&&&&&&&&&&//这里使用MyNullable的有参构造函数&&&&&&&&&&&&};&&&&&&&&&&&&Console.WriteLine('我今年' + p1.Age + '岁。');&&&&&&&&&&&&Console.WriteLine('毛爷爷活了' + p2.Age + '岁。'); &&&&&&&&&&&&Console.ReadKey();&&&&&&&&}&&&&}}
如此,我们已经完成了自定义可空类型的直接赋值。但只是部分,如果想要赋值null呢?同样还是出现了最开始的编译错误。我们想到既然上面的值赋值可以重新(隐式转换),那null应该也可以啊(null是引用类型的一个特定值)。再加一个重载:
//隐式转换public static implicit operator MyNullable(string value){&&&&if (value == null)&&&&&&&&return new MyNullable();&&&&throw new Exception('赋值右边不能为字符串');&&&&//这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)}
如此可以满足我们的需求了(并无异常)。可惜美中不足,如果给&p2.EndTiem&赋值一个非空字符串时,要运行时才会报错(而系统的可空类型会在编译期就报错)。不知道大神们可有解!!虽然如此,能做到直接赋值还是让我小小激动了一把。为此,特意查了下关键字&implicit operator&,又是让我小小激动了一把,我们不仅可以“重写”赋值,我们还可以“重写”+ – * / % & | ^ > == != > =下面我们先来“重写”下自定义可空类型的比较(==)运算符。
12345678910111213141516171819202122
//'重写'比较运算符public static bool operator ==(MyNullable operand, MyNullable operand2){&&&&if (!operand.HasValue & !operand2.HasValue)&&&&{&&&&&&&&return true;&&&&}&&&&else if (operand.HasValue & operand2.HasValue)&&&&{&&&&&&&&if (operand2.Value.Equals(operand.Value))&&&&&&&&{&&&&&&&&&&&&return true;&&&&&&&&}&&&&}&&&&return false;}//'重写'比较运算符public static bool operator !=(MyNullable operand, MyNullable operand2){&&&&return !(operand == operand2);}
12345678910111213
Console.WriteLine('p1.EndTiem == null,' + (p1.EndTiem == null).ToString());Console.WriteLine('p2.EndTiem == null,' + (p2.EndTiem == null).ToString());Console.WriteLine('p1.EndTiem == DateTime.Parse(),' + (p1.EndTiem == DateTime.Parse('')).ToString());Console.WriteLine('p2.EndTiem == DateTime.Parse(),' + (p2.EndTiem == DateTime.Parse('')).ToString());p1.EndTiem = DateTime.Parse('');p2.EndTiem = null;Console.WriteLine();Console.WriteLine('赋值 p1.EndTiem = DateTime.Parse()&&p2.EndTiem = null 后:');Console.WriteLine('p1.EndTiem == null,' + (p1.EndTiem == null).ToString());Console.WriteLine('p2.EndTiem == null,' + (p2.EndTiem == null).ToString());Console.WriteLine('p1.EndTiem == DateTime.Parse(),' + (p1.EndTiem == DateTime.Parse('')).ToString());Console.WriteLine('p2.EndTiem == DateTime.Parse(),' + (p2.EndTiem == DateTime.Parse('')).ToString());
结果完全符合!完整代码如下:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace test{&&&&public class Person&&&&{&&&&&&&&/// &&&&&&&&/// 出生日期&&&&&&&&/// &&&&&&&&public DateTime BeginTime { get; set; }&&&&&&&&/// &&&&&&&&/// 死亡日期&&&&&&&&/// &&&&&&&&public MyNullable EndTiem { get; set; } //这里改用MyNullable&&&&&&&&/// &&&&&&&&/// 年龄&&&&&&&&/// &&&&&&&&public double Age&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (EndTiem.Value - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&else//还没挂&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return (DateTime.Now - BeginTime).Days / 365;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&}&&&&}&&&&public struct MyNullablewhere T : struct&&&&{&&&&&&&&//错误&&&&1&&&&结构不能包含显式的无参数构造函数 &&&&&&&&//还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响&&&&&&&&//public MyNullable()&&&&&&&&//{&&&&&&&&//&&&&this._hasValue =&&&&&&&&//} &&&&&&&&public MyNullable(T value)//有参构造函数&&&&&&&&{&&&&&&&&&&&&this._hasValue = true;&&&&&&&&&&&&this._value = value;&&&&&&&&}&&&&&&&&private bool _hasValue;&&&&&&&&public bool HasValue//是否不为空&&&&&&&&{&&&&&&&&&&&&get { return _hasValue; }&&&&&&&&}&&&&&&&&private T _value;&&&&&&&&public T Value//值&&&&&&&&{&&&&&&&&&&&&get&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (!this._hasValue)//如没有值,还访问就抛出异常&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&throw new InvalidOperationException(' 可为空的对象必须具有一个值');&&&&&&&&&&&&&&&&}&&&&&&&&&&&&&&&&return _value;&&&&&&&&&&&&}&&&&&&&&}&&&&&&&&//隐式转换&&&&&&&&public static implicit operator MyNullable(T value)&&&&&&&&{&&&&&&&&&&&&return new MyNullable(value);&&&&&&&&}&&&&&&&&//隐式转换&&&&&&&&public static implicit operator MyNullable(string value)&&&&&&&&{&&&&&&&&&&&&if (value == null)&&&&&&&&&&&&&&&&return new MyNullable();&&&&&&&&&&&&throw new Exception('赋值右边不能为字符串');&&&&&&&&&&&&//这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)&&&&&&&&}&&&&&&&&//'重写'比较运算符&&&&&&&&public static bool operator ==(MyNullable operand, MyNullable operand2)&&&&&&&&{&&&&&&&&&&&&if (!operand.HasValue & !operand2.HasValue)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&return true;&&&&&&&&&&&&}&&&&&&&&&&&&else if (operand.HasValue & operand2.HasValue)&&&&&&&&&&&&{&&&&&&&&&&&&&&&&if (operand2.Value.Equals(operand.Value))&&&&&&&&&&&&&&&&{&&&&&&&&&&&&&&&&&&&&return true;&&&&&&&&&&&&&&&&}&&&&&&&&&&&&}&&&&&&&&&&&&return false;&&&&&&&&}&&&&&&&&//'重写'比较运算符&&&&&&&&public static bool operator !=(MyNullable operand, MyNullable operand2)&&&&&&&&{&&&&&&&&&&&&return !(operand == operand2);&&&&&&&&}&&&&}&&&&class Program&&&&{&&&&&&&&static void Main(string[] args)&&&&&&&&{&&&&&&&&&&&&Person p1 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse('')&&&&&&&&&&&&};&&&&&&&&&&&&Person p2 = new Person()&&&&&&&&&&&&{&&&&&&&&&&&&&&&&BeginTime = DateTime.Parse(''),&&&&&&&&&&&&&&&&EndTiem = DateTime.Parse('')&&&&&&&&&&&&&&&&//new MyNullable(DateTime.Parse(''))&&&&&&&&&&&&&&&&//这里使用MyNullable的有参构造函数&&&&&&&&&&&&};&&&&&&&&&&&&Console.WriteLine('我今年' + p1.Age + '岁。');&&&&&&&&&&&&Console.WriteLine('毛爷爷活了' + p2.Age + '岁。');&&&&&&&&&&&&Console.WriteLine();&&&&&&&&&&&&Console.WriteLine('p1.EndTiem == null,' + (p1.EndTiem == null).ToString());&&&&&&&&&&&&Console.WriteLine('p2.EndTiem == null,' + (p2.EndTiem == null).ToString());&&&&&&&&&&&&Console.WriteLine('p1.EndTiem == DateTime.Parse(),' + (p1.EndTiem == DateTime.Parse('')).ToString());&&&&&&&&&&&&Console.WriteLine('p2.EndTiem == DateTime.Parse(),' + (p2.EndTiem == DateTime.Parse('')).ToString());&&&&&&&&&&&&p1.EndTiem = DateTime.Parse('');&&&&&&&&&&&&p2.EndTiem = null;&&&&&&&&&&&&Console.WriteLine();&&&&&&&&&&&&Console.WriteLine('赋值 p1.EndTiem = DateTime.Parse()&&p2.EndTiem = null 后:');&&&&&&&&&&&&Console.WriteLine('p1.EndTiem == null,' + (p1.EndTiem == null).ToString());&&&&&&&&&&&&Console.WriteLine('p2.EndTiem == null,' + (p2.EndTiem == null).ToString());&&&&&&&&&&&&Console.WriteLine('p1.EndTiem == DateTime.Parse(),' + (p1.EndTiem == DateTime.Parse('')).ToString());&&&&&&&&&&&&Console.WriteLine('p2.EndTiem == DateTime.Parse(),' + (p2.EndTiem == DateTime.Parse('')).ToString());&&&& &&&&&&&&&&&&Console.ReadKey();&&&&&&&&}&&&&}}
转换关键字:operator、explicit与implicit解析资料:大家还可以玩出更多的花样!!!
加入伯乐在线专栏作者。扩大知名度,还能得赞赏!详见《》
发表评论:
TA的最新馆藏}

我要回帖

更多关于 鬼到底是什么 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信