先贴下Nullable<T>简单实现:
[Serializable]
public struct Nulllable<T> where T : struct
{
private Boolean hasValue = false;
internal T value = default(T);
public void Nullable(T value)
{
this.value = value;
this.hasValue = true;
}
public Boolean HashValue
{
get { return this.hasValue; }
}
public T Value
{
get
{
if (!hasValue)
{
throw new InvalidCastException("nullable Object mush have a value");
}
return value;
}
}
public T GetValueOrDefault()
{
return value;
}
public T GetValueOrDefault(T defaultValue)
{
if (!HashValue)
return defaultValue;
return value;
}
public override bool Equals(object other)
{
if (!HashValue)
return (other == null);
if (other == null)
return false;
return value.Equals(other);
}
public override int GetHashCode()
{
if (!HashValue)
return 0;
return value.GetHashCode();
}
public override string ToString()
{
if (!HashValue) return "";
return value.ToString();
}
public static implicit operator Nullable<T>(T value)
{
return new Nullable<T>(value);
}
public static explicit operator T(Nullable<T> value)
{
return value.Value;
}
}
}
大家可以看到 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;
}
}
}
没错这也是完全正确的!