【转】四、可空类型Nullable到底是什么不良。【转】四、可空类型Nullable到底是呀破。

【转】四、可空类型Nullable<T>到底是呀不好

【转】四、可空类型Nullable<T>到底是呀破

值类型为什么不可以吧空

率先我们且懂引用类型默认值都是null,而值类型的默认值都起非null。

必威网站 1

为何引用类型可以为空?因为引用类型变量都是保留一个对象的地点引用(就如一个url对诺一个页面),而引用类型值为null的当儿是变量值指向了一个拖欠引用(如同一个缺损的url)

必威网站 2

这就是说干什么值未可知起空值呢?其实深简单,因为要是int值范围是-2147483648到2147483647。其中向就没叫null值留那么一个职务。

必威网站 3

值类型为什么未得以吗空

首先我们都晓得引用类型默认值都是null,而值类型的默认值都发生非null。

必威网站 4

干什么引用类型可以吧空?因为引用类型变量都是保存一个靶的地方引用(就比如一个url对诺一个页面),而引用类型值为null的上是变量值指向了一个空引用(如同一个拖欠的url)

必威网站 5

那么怎么值未克闹空值呢?其实挺简短,因为只要int值范围是-2147483648到2147483647。其中向就是从未有过受null值留那么一个职位。

必威网站 6

咱怎么要为此到可空类型

推个栗子吧,我们定义一个人数(Person),它发生三只属性出生日期(BeginTime)、死亡日期(EndTime)、年龄(Age)。

而这人尚健在凡间,请问怎么受死亡日期赋值?有人死聪明伶俐说“为空啊”。是的,这就是我们的需。

微软在C#2.0底时节即便吧我们引入了可null值类型( System.Nullable<T> ),那么下来定义Person类。

 1 public class Person
 2 {
 3     /// <summary>
 4     /// 出生日期
 5     /// </summary>
 6     public DateTime BeginTime { get; set; }
 7     /// <summary>
 8     /// 死亡日期
 9     /// </summary>
10     public System.Nullable<DateTime> EndTiem { get; set; }
11     public int Age
12     {
13         get
14         {
15             if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
16             {
17                 return (EndTiem.Value - BeginTime).Days;
18             }
19             else//还没挂
20             {
21                 return (DateTime.Now - BeginTime).Days;
22             }
23         }
24     }
25 }

 

这么,我们不怕足以十分容易得到一个总人口之年了。

static void Main(string[] args)
{
    Person p1 = new Person()
    {
        BeginTime = DateTime.Parse("1990-07-19")
    };

    Person p2 = new Person()
    {
        BeginTime = DateTime.Parse("1893-12-26"),
        EndTiem = DateTime.Parse("1976-09-09")
    };

    Console.WriteLine("我今年" + p1.Age + "岁。");
    Console.WriteLine("毛爷爷活了" + p2.Age + "岁。");

    Console.ReadKey();
}

俺们为什么用用到可空类型

推选个栗子吧,我们定义一个丁(Person),它发出三个特性出生日期(BeginTime)、死亡日期(EndTime)、年龄(Age)。

如是人还善于在人间,请问怎么叫已故日期赋值?有人大明白说“为空啊”。是的,这即是咱们的求。

微软在C#2.0之当儿便也咱引入了可null值类型( System.Nullable<T> ),那么下面来定义Person类。

 1 public class Person
 2 {
 3     /// <summary>
 4     /// 出生日期
 5     /// </summary>
 6     public DateTime BeginTime { get; set; }
 7     /// <summary>
 8     /// 死亡日期
 9     /// </summary>
10     public System.Nullable<DateTime> EndTiem { get; set; }
11     public int Age
12     {
13         get
14         {
15             if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
16             {
17                 return (EndTiem.Value - BeginTime).Days;
18             }
19             else//还没挂
20             {
21                 return (DateTime.Now - BeginTime).Days;
22             }
23         }
24     }
25 }

 

然,我们就是可老轻得一个丁的年华了。

static void Main(string[] args)
{
    Person p1 = new Person()
    {
        BeginTime = DateTime.Parse("1990-07-19")
    };

    Person p2 = new Person()
    {
        BeginTime = DateTime.Parse("1893-12-26"),
        EndTiem = DateTime.Parse("1976-09-09")
    };

    Console.WriteLine("我今年" + p1.Age + "岁。");
    Console.WriteLine("毛爷爷活了" + p2.Age + "岁。");

    Console.ReadKey();
}

但是空类型的兑现

咱俩前用到了 System.Nullable<DateTime> 来代表可空时间项目,其实平时咱们为此得重新多之凡 DateTime? 直接在类型T后当加一个问号,这半栽是平等的。多亏了微软的语法糖。

咱们来看看 System.Nullable<T> 到底是何物。

必威网站 7

搜噶,原来是一个布局。还看到了俺们属性的
HasValue和Value属性。原来竟然这么简单。一个构造简单只属性,一个存值,一个抱是否有价。那么下面我们为来试试看吧。

必威网站 8

不好意思,让大家失望了。前面我们便说了了,值类型是勿得以赋值null的(结构也是值类型)。

怎收拾!怎么收拾!不对啊,微软团结吧是概念的结构,它怎么好一直赋值null呢。(奇怪,奇怪,毕竟是家微软自己为得,可能赢得了异常的对吧)

不过,这样即便深受咱们止步了呢?NO!我们且知道,看微软的IL(中间语言)的时刻,就如脱了其的装一样,很多下不晓的地方还可以拘留个究竟,下面我们就算失去排除衣服。

第一,我们用几种植不同之不二法门吃可空类型赋值。

static void Main(string[] args)
{

    System.Nullable<int> number1 = null;

    System.Nullable<int> number2 = new System.Nullable<int>();

    System.Nullable<int> number3 = 23;

    System.Nullable<int> number4 = new System.Nullable<int>(88);

    Console.ReadKey();
}    

 

然后据此reflector看编译后的IL。

必威网站 9

原来如此,可空类型的赋值直接当效于构造实例。赋null时其实就是是调动用空构造函数,有值时虽即拿价值传入带参数的构造函数。(柳暗花明又一村。如此,我们是否足以跟着上面截图中的 MyNullable<T> 继续学可空类型呢?且连续于生看。)

public struct MyNullable<T> where T : struct
{
    //错误    1    结构不能包含显式的无参数构造函数 
    //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
    //public MyNullable()
    //{
    //    this._hasValue = false;
    //}
    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;
        }
    }
}

 

哟西,基本上已经拟出了可空类型出来的。(但是咱尚是匪克直接赋值,只能通过构造函数的办法来使用从定义的可空类型)。

整套代码如下:

必威网站 10必威网站 11

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 可空类型
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //}
        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("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))//这里使用MyNullable的有参构造函数
            };

            Console.WriteLine("我今年" + p1.Age + "岁。");
            Console.WriteLine("毛爷爷活了" + p2.Age + "岁。");

            Console.ReadKey();
        }

    }
}

View Code

 

及体系的可空类型得出了同一之结果。

必威网站 12

可空类型的实现

咱前用到了 System.Nullable<DateTime> 来表示可空时间项目,其实平时咱们所以得又多的凡 DateTime? 直接当类型T后当加一个问号,这简单种植是如出一辙的。多亏了微软的语法糖。

咱们来看望 System.Nullable<T> 到底是何物。

必威网站 13

搜噶,原来是一个构造。还见到了咱们属性的
HasValue和Value属性。原来竟是这么简单。一个构造简单只属性,一个存值,一个满怀是否生价。那么下我们呢来试吧。

必威网站 14

不好意思,让大家失望了。前面我们不怕说了了,值类型是休得以赋值null的(结构也是值类型)。

怎么收拾!怎么收拾!不对啊,微软协调吗是概念之布局,它怎么好一直赋值null呢。(奇怪,奇怪,毕竟是每户微软自己打出得,可能获取了独特之对待吧)

可,这样即使给咱止步了啊?NO!我们都明白,看微软的IL(中间语言)的时刻,就比如脱了其的服装一样,很多时节不知晓的地方还足以扣押个究竟,下面我们就是失排除衣服。

先是,我们就此几种植不同的点子吃可空类型赋值。

static void Main(string[] args)
{

    System.Nullable<int> number1 = null;

    System.Nullable<int> number2 = new System.Nullable<int>();

    System.Nullable<int> number3 = 23;

    System.Nullable<int> number4 = new System.Nullable<int>(88);

    Console.ReadKey();
}    

 

然后用reflector看编译后底IL。

必威网站 15

原来如此,可空类型的赋值直接当效于构造实例。赋null时其实就是调动用空构造函数,有值时就不怕管价值传入带参数的构造函数。(柳暗花明又一村。如此,我们是不是可以接着上面截图中之 MyNullable<T> 继续学可空类型呢?且持续往生看。)

public struct MyNullable<T> where T : struct
{
    //错误    1    结构不能包含显式的无参数构造函数 
    //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
    //public MyNullable()
    //{
    //    this._hasValue = false;
    //}
    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;
        }
    }
}

 

哟西,基本上就拟出了可空类型出来的。(但是咱尚是免可知直接赋值,只能通过构造函数的道来利用自定义之可空类型)。

全方位代码如下:

必威网站 16必威网站 17

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace 可空类型
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //}
        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("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))//这里使用MyNullable的有参构造函数
            };

            Console.WriteLine("我今年" + p1.Age + "岁。");
            Console.WriteLine("毛爷爷活了" + p2.Age + "岁。");

            Console.ReadKey();
        }

    }
}

View Code

 

与网的可空类型得出了相同的结果。

必威网站 18

总结

  • 唯独空类型是构造(也就是值类型)
  • 因此只是空类型的null值和援类型的null是无一样的。(可空类型的并无是援引类型的null,而是用结构的其他一样种植象征法来代表null)

必威网站 19

 

发同学咨询,怎么样才可以成功直接赋值呢?这个自家呢尚无啊好的措施,或许用编译器的支撑。

如上内容还是戏说。希望会对您发出那么一点点为此处,感谢阅读。

(首发链接:http://www.cnblogs.com/zhaopei/p/5537759.html )

 

 


 

============== 2016-06-05更新==============

方我们提出了疑义“安才得以好直接赋值呢”,本来我是从未好之解决办法。这里要感谢咱的园友@冲杀吃自身提供了好的缓解方案。

implicit(关键字用于声明隐式的用户定义类型转换运算符。)

public static implicit operator MyNullable<T>(T value)
{
       return new MyNullable<T>(value);
}

只有需要在 struct
MyNullable<T> 中添加之上代码,就好一直赋值了。(作用等效于是直还写了“=”赋值符号)

必威网站 20

必威网站 21

圆代码如下:

必威网站 22必威网站 23

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //} 

        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>(T value)
        {
            return new MyNullable<T>(value);
        } 
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person()
            {
                BeginTime = DateTime.Parse("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = DateTime.Parse("1976-09-09") 
                //new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))
                //这里使用MyNullable的有参构造函数
            };

            Console.WriteLine("我今年" + p1.Age + "岁。");
            Console.WriteLine("毛爷爷活了" + p2.Age + "岁。"); 

            Console.ReadKey();
        }

    }
}

View Code

 

然,我们曾做到了从定义可空类型的第一手赋值。但偏偏是有些,如果想使赋值null呢?

必威网站 24

无异于还是出现了最初步之编译错误。我们想到既然点的价值赋值可以还(隐式转换),那null应该为足以啊(null是援类型的一个特定值)。

重复加一个重载:

//隐式转换
public static implicit operator MyNullable<T>(string value)
{
    if (value == null)
        return new MyNullable<T>();
    throw new Exception("赋值右边不能为字符串");
    //这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)
}

 

这样可以满足我们的急需了(并随便不胜)。

必威网站 25

心疼美被欠缺,如果为 p2.EndTiem 赋值一个非空字符串时,要运行时才见面报错(而网的可空类型会于编译期就报错)。不清楚大神们可有解!!

则这样,能做到直接赋值还是叫自身小小激动了扳平拿。为这个,特意查看了下第一字 implicit operator ,又是吃自家小小激动了同样管,我们不但可“重写”赋值,我们还足以“重写”+

  • * / % & | ^ << >> == != > < >= <=等运算符。

下面我们先行来“重写”下从定义可空类型的比较(==)运算符。

//"重写"比较运算符
public static bool operator ==(MyNullable<T> operand, MyNullable<T> 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<T> operand, MyNullable<T> operand2)
{
    return !(operand == operand2);
}

 

Console.WriteLine("p1.EndTiem == null," + (p1.EndTiem == null).ToString());
Console.WriteLine("p2.EndTiem == null," + (p2.EndTiem == null).ToString());
Console.WriteLine("p1.EndTiem == DateTime.Parse(1976-09-09)," + (p1.EndTiem == DateTime.Parse("1976-09-09")).ToString());
Console.WriteLine("p2.EndTiem == DateTime.Parse(1976-09-09)," + (p2.EndTiem == DateTime.Parse("1976-09-09")).ToString());

p1.EndTiem = DateTime.Parse("2016-06-06");
p2.EndTiem = null;
Console.WriteLine();
Console.WriteLine("赋值 p1.EndTiem = DateTime.Parse(2016-06-06)  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(2016-06-06)," + (p1.EndTiem == DateTime.Parse("2016-06-06")).ToString());
Console.WriteLine("p2.EndTiem == DateTime.Parse(2016-06-06)," + (p2.EndTiem == DateTime.Parse("2016-06-06")).ToString());

必威网站 26

结果完全符合!

整体代码如下:

必威网站 27必威网站 28

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //} 

        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>(T value)
        {
            return new MyNullable<T>(value);
        }

        //隐式转换
        public static implicit operator MyNullable<T>(string value)
        {
            if (value == null)
                return new MyNullable<T>();
            throw new Exception("赋值右边不能为字符串");
            //这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)
        }

        //"重写"比较运算符
        public static bool operator ==(MyNullable<T> operand, MyNullable<T> 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<T> operand, MyNullable<T> operand2)
        {
            return !(operand == operand2);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person()
            {
                BeginTime = DateTime.Parse("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = DateTime.Parse("1976-09-09")
                //new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))
                //这里使用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(1976-09-09)," + (p1.EndTiem == DateTime.Parse("1976-09-09")).ToString());
            Console.WriteLine("p2.EndTiem == DateTime.Parse(1976-09-09)," + (p2.EndTiem == DateTime.Parse("1976-09-09")).ToString());

            p1.EndTiem = DateTime.Parse("2016-06-06");
            p2.EndTiem = null;
            Console.WriteLine();
            Console.WriteLine("赋值 p1.EndTiem = DateTime.Parse(2016-06-06)  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(2016-06-06)," + (p1.EndTiem == DateTime.Parse("2016-06-06")).ToString());
            Console.WriteLine("p2.EndTiem == DateTime.Parse(2016-06-06)," + (p2.EndTiem == DateTime.Parse("2016-06-06")).ToString());     

            Console.ReadKey();
        }

    }
}

View Code

 

 

易关键字:operator、explicit与implicit解析资料:http://www.cnblogs.com/hunts/archive/2007/01/17/operator_explicit_implicit.html

大家还可以玩出更多的花头!!!

 

本文就联名到《C#基础知识巩固系列》

总结

  • 而空类型是构造(也不怕是值类型)
  • 就此只是空类型的null值和援类型的null是免同等的。(可空类型的并无是援引类型的null,而是用结构的另外一样栽表示方法来表示null)

必威网站 29

 

发出同学咨询,怎么样才得做到直接赋值呢?这个自己耶尚无啊好的措施,或许用编译器的支撑。

如上内容都是乱说。希望会针对你来那么一点点所以处,感谢阅读。

(首发链接:http://www.cnblogs.com/zhaopei/p/5537759.html )

 

 


 

============== 2016-06-05更新==============

地方我们提出了疑义“什么样才得成功直接赋值呢”,本来我是绝非好的解决办法。这里要感谢咱的园友@冲杀给自身提供了好的化解方案必威网站。

implicit(关键字用于声明隐式的用户定义类型转换运算符。)

public static implicit operator MyNullable<T>(T value)
{
       return new MyNullable<T>(value);
}

无非待以 struct
MyNullable<T> 中添加以上代码,就好直接赋值了。(作用等效于是直还写了“=”赋值符号)

必威网站 30

必威网站 31

完全代码如下:

必威网站 32必威网站 33

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //} 

        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>(T value)
        {
            return new MyNullable<T>(value);
        } 
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person()
            {
                BeginTime = DateTime.Parse("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = DateTime.Parse("1976-09-09") 
                //new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))
                //这里使用MyNullable的有参构造函数
            };

            Console.WriteLine("我今年" + p1.Age + "岁。");
            Console.WriteLine("毛爷爷活了" + p2.Age + "岁。"); 

            Console.ReadKey();
        }

    }
}

View Code

 

如此,我们已经就了打定义可空类型的直白赋值。但不过是片,如果想要赋值null呢?

必威网站 34

一如既往要出现了最好初步的编译错误。我们想到既然点的价赋值可以重复(隐式转换),那null应该也可啊(null是引用类型的一个特定值)。

又加一个重载:

//隐式转换
public static implicit operator MyNullable<T>(string value)
{
    if (value == null)
        return new MyNullable<T>();
    throw new Exception("赋值右边不能为字符串");
    //这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)
}

 

这般可以满足我们的求了(并凭异常)。

必威网站 35

心疼美中欠缺,如果被 p2.EndTiem 赋值一个非空字符串时,要运行时才见面报错(而系统的可空类型会于编译期就报错)。不清楚大神们可有解!!

虽说这么,能成功直接赋值还是于自身小小激动了同样拿。为之,特意查看了生主要字 implicit operator ,又是受自己不大激动了一致将,我们不光可以“重写”赋值,我们还足以“重写”+

  • * / % & | ^ << >> == != > < >= <=等运算符。

下面我们先行来“重写”下于定义可空类型的比(==)运算符。

//"重写"比较运算符
public static bool operator ==(MyNullable<T> operand, MyNullable<T> 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<T> operand, MyNullable<T> operand2)
{
    return !(operand == operand2);
}

 

Console.WriteLine("p1.EndTiem == null," + (p1.EndTiem == null).ToString());
Console.WriteLine("p2.EndTiem == null," + (p2.EndTiem == null).ToString());
Console.WriteLine("p1.EndTiem == DateTime.Parse(1976-09-09)," + (p1.EndTiem == DateTime.Parse("1976-09-09")).ToString());
Console.WriteLine("p2.EndTiem == DateTime.Parse(1976-09-09)," + (p2.EndTiem == DateTime.Parse("1976-09-09")).ToString());

p1.EndTiem = DateTime.Parse("2016-06-06");
p2.EndTiem = null;
Console.WriteLine();
Console.WriteLine("赋值 p1.EndTiem = DateTime.Parse(2016-06-06)  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(2016-06-06)," + (p1.EndTiem == DateTime.Parse("2016-06-06")).ToString());
Console.WriteLine("p2.EndTiem == DateTime.Parse(2016-06-06)," + (p2.EndTiem == DateTime.Parse("2016-06-06")).ToString());

必威网站 36

结果完全符合!

完代码如下:

必威网站 37必威网站 38

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace test
{
    public class Person
    {
        /// <summary>
        /// 出生日期
        /// </summary>
        public DateTime BeginTime { get; set; }
        /// <summary>
        /// 死亡日期
        /// </summary>
        public MyNullable<DateTime> EndTiem { get; set; } //这里改用MyNullable
        /// <summary>
        /// 年龄
        /// </summary>
        public double Age
        {
            get
            {
                if (EndTiem.HasValue)//如果挂了(如果有值,证明死了)
                {
                    return (EndTiem.Value - BeginTime).Days / 365;
                }
                else//还没挂
                {
                    return (DateTime.Now - BeginTime).Days / 365;
                }
            }
        }
    }

    public struct MyNullable<T> where T : struct
    {
        //错误    1    结构不能包含显式的无参数构造函数 
        //还好 bool默认值就是false,所以这里不显示为 this._hasValue = false也不会有影响
        //public MyNullable()
        //{
        //    this._hasValue = false;
        //} 

        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>(T value)
        {
            return new MyNullable<T>(value);
        }

        //隐式转换
        public static implicit operator MyNullable<T>(string value)
        {
            if (value == null)
                return new MyNullable<T>();
            throw new Exception("赋值右边不能为字符串");
            //这里不知道是否可以在编译期间抛出错误(或者怎样限制只能传null)
        }

        //"重写"比较运算符
        public static bool operator ==(MyNullable<T> operand, MyNullable<T> 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<T> operand, MyNullable<T> operand2)
        {
            return !(operand == operand2);
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            Person p1 = new Person()
            {
                BeginTime = DateTime.Parse("1990-07-19")
            };

            Person p2 = new Person()
            {
                BeginTime = DateTime.Parse("1893-12-26"),
                EndTiem = DateTime.Parse("1976-09-09")
                //new MyNullable<DateTime>(DateTime.Parse("1976-09-09"))
                //这里使用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(1976-09-09)," + (p1.EndTiem == DateTime.Parse("1976-09-09")).ToString());
            Console.WriteLine("p2.EndTiem == DateTime.Parse(1976-09-09)," + (p2.EndTiem == DateTime.Parse("1976-09-09")).ToString());

            p1.EndTiem = DateTime.Parse("2016-06-06");
            p2.EndTiem = null;
            Console.WriteLine();
            Console.WriteLine("赋值 p1.EndTiem = DateTime.Parse(2016-06-06)  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(2016-06-06)," + (p1.EndTiem == DateTime.Parse("2016-06-06")).ToString());
            Console.WriteLine("p2.EndTiem == DateTime.Parse(2016-06-06)," + (p2.EndTiem == DateTime.Parse("2016-06-06")).ToString());     

            Console.ReadKey();
        }

    }
}

View Code

 

 

更换关键字:operator、explicit与implicit解析资料:http://www.cnblogs.com/hunts/archive/2007/01/17/operator_explicit_implicit.html

大家还可玩出更多的花样!!!

 

正文就联合到《C#基础知识巩固系列》

相关文章