歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

C#可空類型

在程序開發中,有時候需要值類型也為可空類型,比如,在數據庫中,我們可以把一個日期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的一個以裝箱的值

  • 已裝箱的值可以拆箱成普通類型,或者拆箱為對於的可空類型
    • 拆箱一個空引用時,如果拆箱為普通類型,會拋出一個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 : struct
public 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#委托的基本概念 http://www.linuxidc.com/Linux/2015-02/113470.htm
  • 進一步理解C#委托 http://www.linuxidc.com/Linux/2015-02/113469.htm
  • C#多線程編程實例 線程與窗體交互【附源碼】 http://www.linuxidc.com/Linux/2014-07/104294.htm
  • C#數學運算表達式解釋器 http://www.linuxidc.com/Linux/2014-07/104289.htm
  • 在C語言中解析JSON配置文件 http://www.linuxidc.com/Linux/2014-05/101822.htm
  • C++ Primer Plus 第6版 中文版 清晰有書簽PDF+源代碼 http://www.linuxidc.com/Linux/2014-05/101227.htm

Copyright © Linux教程網 All Rights Reserved