为什么Nullable<T>结构能为null


先贴下Nullable<T>简单实现:

 1 [Serializable]
2 public struct Nulllable<T> where T : struct
3 {
4 private Boolean hasValue = false;
5 internal T value = default(T);
6 public void Nullable(T value)
7 {
8 this.value = value;
9 this.hasValue = true;
10 }
11 public Boolean HashValue
12 {
13 get { return this.hasValue; }
14 }
15 public T Value
16 {
17 get
18 {
19 if (!hasValue)
20 {
21 throw new InvalidCastException("nullable Object mush have a value");
22 }
23 return value;
24 }
25 }
26 public T GetValueOrDefault()
27 {
28 return value;
29 }
30 public T GetValueOrDefault(T defaultValue)
31 {
32 if (!HashValue)
33 return defaultValue;
34 return value;
35 }
36 public override bool Equals(object other)
37 {
38 if (!HashValue)
39 return (other == null);
40 if (other == null)
41 return false;
42 return value.Equals(other);
43 }
44 public override int GetHashCode()
45 {
46 if (!HashValue)
47 return 0;
48 return value.GetHashCode();
49 }
50 public override string ToString()
51 {
52 if (!HashValue) return "";
53 return value.ToString();
54 }
55 public static implicit operator Nullable<T>(T value)
56 {
57 return new Nullable<T>(value);
58 }
59 public static explicit operator T(Nullable<T> value)
60 {
61 return value.Value;
62 }
63
64 }
65 }



大家可以看到 public struct Nulllable<T> where T : struct

Nulllable<T>为值类型 同样 T 也为值类型 理论上 Nulllable<T> 不可能跟null扯上关系

那为什么 Nulllable<Int32> temp = null;  那这个null 去那了呢?

下面就通过IL来看看到底发生了什么吧!

第一次:

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

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Nullable<Int32> temp = null;
}
}
}

对应的IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// 代码大小 10 (0xa)
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> temp)
IL_0000: nop
IL_0001: ldloca.s temp
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ret
} // end of method Program::Main

 

从这里可以看到他这里只是往栈里压了一个 压了一个变量 大家完全可以理解为  Nullable<Int32> temp;

 

  this.value = 0; 因为default(T)
  this.hasValue = false;

 

接下来 :

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

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Nullable<Int32> temp = 22;
}
}
}


IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// 代码大小 12 (0xc)
.maxstack 2
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> temp)
IL_0000: nop
IL_0001: ldloca.s temp
IL_0003: ldc.i4.s 22
IL_0005: call instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)
IL_000a: nop
IL_000b: ret
} // end of method Program::Main


看到了没  区别在:  IL_0005:  call       instance void valuetype [mscorlib]System.Nullable`1<int32>::.ctor(!0)

他执行了构造函数;

此时:

public void Nullable(T value)
  {
  this.value = value;
  this.hasValue = true;
  }

this.value = 22;

this.hasValue = true;

 

接下来:

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

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Nullable<Int32> temp = null;
if (temp == null)
{
}
}
}
}

 

IL:

.method private hidebysig static void  Main(string[] args) cil managed
{
.entrypoint
// 代码大小 23 (0x17)
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> temp,
[1] bool CS$4$0000)
IL_0000: nop
IL_0001: ldloca.s temp
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloca.s temp
IL_000b: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0010: stloc.1
IL_0011: ldloc.1
IL_0012: brtrue.s IL_0016
IL_0014: nop
IL_0015: nop
IL_0016: ret
} // end of method Program::Main


这里的IF执行的是什么呢?

他首先会去检查里面有没有值  IL_000b:  call       instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()

 

看到这里大家有没有发现这个null那都没用到!没错  其实这里c#编辑器跟我们玩了个魔术 !

 

看到这里肯定有人会这么写代码:

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

namespace ConsoleApplication3
{
class Program
{
static void Main(string[] args)
{
Nullable<Int32> temp = new Nullable<Int32>(); //相当于 Nullable<Int32> temp = null;
Nullable<Int32> temp1 = new Nullable<Int32>(22); //相当于 Nullable<Int32> temp = 22;
}
}
}

 

没错这也是完全正确的!

 

编译器成功骗过了我们追求真理程序猿!

转载于:https://www.cnblogs.com/skolley/archive/2011/12/17/2291370.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值