.NET裡的變數型別分為Value Type(如int, bool)與Reference Type(如StringBuilder, SqlConnection),其中Value Type的資料內容直接放在堆疊(Stack)中,不像Reference Type需要Pointer指向真正的資料位置,因而Value Type的變數沒法指定為null。(延伸閱讀: 1 2)

.NET 2.0提供了Nullable Value Type,實際上是用一個泛型結構(Generic Structure)去包裝Value Type,詳細的說明請大家看官方文件,這裡就不雞婆了。我學習Nullable Type時,只看了Nullable Structure Members文件就匆匆用了起來(其實我應該先看看Using Nullable Type的),關於資料是否為null的判斷就乖乖地寫成: if (i.HasValue) { j=i.Value; }

昨天同事小娟跟我說她測試的結果,其實寫: if (i==null) { j=i; }就可以了(驚! 我當了好一陣子的笨蛋)

親手做了測試,i==null的寫法OK,j=i的寫法有個但書,就是j必須跟i一樣是Nullable Type,不然Compile時會出錯。不過,我們共同的疑問是,i==null與i.HasValue的寫法當真完全相同? 會不會在某些情境下有特殊限制?

我驗證這個問題的方法是寫了如下的Code,Build成EXE檔後,再用ILDASM反組譯。

static void TestNullable()
{
    int? i = null;
    if (i == null)
        Console.WriteLine("i == null");
    if (!i.HasValue)
        Console.WriteLine("i has value");
    int? x = i;
    int y = i.Value;
}

ILDASM反組譯的結果,可以看到i==null與i.HasValue最後會被編譯成完全相同的MSIL Code。

.method private hidebysig static void TestNullable() cil managed
{
// Code size 64 (0x40)
.maxstack 1
.locals init ([0] valuetype [mscorlib]System.Nullable`1<int32> i,
[1] valuetype [mscorlib]System.Nullable`1<int32> x,
[2] int32 y,
[3] bool CS$4$0000)
IL_0000: nop
IL_0001: ldloca.s i
IL_0003: initobj valuetype [mscorlib]System.Nullable`1<int32>
IL_0009: ldloca.s i
IL_000b: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0010: stloc.3
IL_0011: ldloc.3
IL_0012: brtrue.s IL_001f
IL_0014: ldstr "i == null"
IL_0019: call void [mscorlib]System.Console::WriteLine(string)
IL_001e: nop
IL_001f: ldloca.s i
IL_0021: call instance bool valuetype [mscorlib]System.Nullable`1<int32>::get_HasValue()
IL_0026: stloc.3
IL_0027: ldloc.3
IL_0028: brtrue.s IL_0035
IL_002a: ldstr "i has value"
IL_002f: call void [mscorlib]System.Console::WriteLine(string)
IL_0034: nop
IL_0035: ldloc.0
IL_0036: stloc.1
IL_0037: ldloca.s i
IL_0039: call instance !0 valuetype [mscorlib]System.Nullable`1<int32>::get_Value()
IL_003e: stloc.2
IL_003f: ret
} // end of method Program::TestNullable

由以上的分析來看,在C#中可以直接引用i==null,應該算是C# Compiler(CSC.EXE)的佛心來著,而我們在撰寫相關程式碼時,就大大方方享受這項貼心服務吧!


Comments

# by chicken

c# compiler 藏太多 syntax candy, 常常讓你搞不清楚到底發生啥事... 不過加好還是不加好? 當然是加... :D

# by I'm Ant Only

>>Value Type的變數沒法指定為null 應該可以,不過就相當於 re-initialize value. e.g. int i = null; '// i == 0 Nullable<T>是Structure/Value Type,只是它的Null值是 Nullable<int> Ni = null; '// Ni.hasValue = false '// Ni.Value = undefined (InvalidOperationException)

# by Jeffrey

To "I'm Ant Only": int i=null;的寫法應該在Build時就會引發Cannot convert null to 'int' because it is a non-nullable value type的錯誤,還是我誤解了您的意思?

Post a comment