C#可空類型

來源:互聯網
上載者:User

標籤:

在程式開發中,有時候需要實值型別也為可空類型,比如,在資料庫中,我們可以把一個日期Datetime設定為null。

在C# 2.0中就出現了可空類型,允許實值型別也可以為空白(null),可空類型的實現基於C#泛型。

可空類型基本知識

可空類型的核心是System.Nullable<T>,同時靜態類System.Nullable為可空類型提供了很多實用的方法。下面分別看看可空類型的這兩個重要組成部分。

System.Nullable<T>

通過ILSpy我們可以查看這個類型的C#代碼:

從上面的圖中可以看到關於System.Nullable<T>的一些關鍵點:

  1. Nullable<T>是一個泛型型別
  2. 型別參數T有一個實值型別的約束(根據實值型別約束T : struct,T不能為可空類型,也就是說Nullable<Nullable<int>>是不允許的)
  3. Nullable<T>是一個實值型別(是一個struct)

對於任何具體的可空類型來說,T的類型為可空類型的基礎類型(underlying type),例如Nullable<int>的基礎類型就是int。

通過上面代碼還可以看到,Nullable<T>有兩個重要的屬性,HasValue和Value。通過它們可以瞭解可空類型是怎麼工作的:

  1. 如果一個可空實值型別存在一個真正的值,那麼Value就代表這個值本身,同時HasValue值為true
  2. 如果一個可空實值型別為空白,那麼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代碼是一樣的:

C#代碼

Nullable<int> x = 5;x = new Nullable<int>(9);

IL代碼

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的一個以裝箱的值

  • 已裝箱的值可以拆箱成普通類型,或者拆箱為對於的可空類型
    • 拆箱一個Null 參考時,如果拆箱為普通類型,會拋出一個NullReferenceException的異常
    • 如果拆箱成恰當的可控類型,就會拆箱成一個沒有值的Nullable<T>執行個體

看一個關於可空類型裝箱和拆箱的例子:

static void Main(string[] args){    Nullable<int> x = 5;    //有值的可空類型裝箱    object boxed = x;    Console.WriteLine(x.GetType());    //拆箱為普通類型    int normal = (int)boxed;    Console.WriteLine(normal);    //拆箱為可空類型    x = (Nullable<int>)boxed;    Console.WriteLine(x);    x = new Nullable<int>();    //空的可空類型裝箱    boxed = x;    Console.WriteLine(boxed == null);    //拆箱為可空類型    x = (Nullable<int>)boxed;    Console.WriteLine(x.HasValue);         }

輸出:

System.Nullable

System.Nullable是一個靜態類,只包含三個靜態方法,大家可以通過ILSpy進行查看,這裡就不了。

下面兩個方法是比較方法:

public static int Compare<T>(T? n1, T? n2) where T : structpublic 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#可空類型

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.