国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

C#基礎語法:可空類型詳解

2020-01-24 01:41:51
字體:
來源:轉載
供稿:網友

以下是System.Nullable<T>在FCL中的定義。

[Serializable, StructLayout(LayoutKind.Sequential)]public struct Nullable<T> where T :struct{ private Boolean hasValue= false; internal T value= default(T);public Nullable(T value) {this.value= value;this.hasValue= true; }public Boolean HasValue {get {return hasValue; } }public T Value {get  {  if (!hasValue)    {   throw new InvalidOperationException("Nullable object must have a value.");    }   return value;  } }public T GetValueOrDefault() {return value; }public T GetValueOrDefault(T defaultValue) {if(!HasValue)return defaultValue;return value; }public override Boolean Equals(object other) {if(!HasValue)return (other== null);if(other== null)return false;return value.Equals(other); }public override int GetHashCode() {if(!HasValue)return 0;return value.GetHashCode(); }public override string ToString() {if(!HasValue)return "";return value.ToString(); }public static implicit operator Nullable<T>(T value) {return new Nullable<T>(value); }}

可以看出 null 的類型的每個實例都具有兩個公共的只讀屬性:

1.HasValue

HasValue 屬于 bool 類型。當變量包含非 null 值時,它被設置為 true。

2.Value

Value 的類型與基礎類型相同。如果 HasValue 為 true,則說明 Value 包含有意義的值。如果 HasValue 為 false,則訪問 Value 將引發 InvalidOperationException。

那么我們怎么定義可空類型?

null 的類型可通過下面兩種方式中的一種聲明:

復制代碼 代碼如下:

System.Nullable<T> variable

- 或 -

T? variable


T 是可以為 null 的類型的基礎類型。T 可以是包括 struct 在內的任何值類型;但不能是引用類型。

現在舉一個例子,運用一下看看效果是不是一樣。

Console.WriteLine("========可空類型操作演示========/n");      Console.WriteLine("/n=========Nullable<T>===========/n");      Nullable<int> x = 5;      Nullable<bool> y = false;      Nullable<double> z = 5.20;      Nullable<char> n = null;      Console.WriteLine("x.HasValue={0},   x.Value={1}",x.HasValue,x.Value);      Console.WriteLine("y.HasValue={0},   y.Value={1}", y.HasValue, y.Value);      Console.WriteLine("z.HasValue={0},   z.Value={1}", z.HasValue, z.Value);      Console.WriteLine("n.HasValue={0},   n.Value={1}",n.HasValue, n.GetValueOrDefault());      Console.WriteLine("/n============== T? ============/n");      int? X = 5;      bool? Y = false;      double? Z = 5.20;      char? N = null;      int?[] arr ={1,2,3,4,5};//一個可空類型的數組      Console.WriteLine("X.HasValue={0},   X.Value={1}", X.HasValue,X.Value);      Console.WriteLine("y.HasValue={0},   Y.Value={1}", Y.HasValue, Y.Value);      Console.WriteLine("Z.HasValue={0},   Z.Value={1}", Z.HasValue, Z.Value);      Console.WriteLine("N.HasValue={0},   N.Value={1}", N.HasValue, N.GetValueOrDefault());      Console.WriteLine("/n================================/n");      Console.ReadKey();

可空類型可強制轉換為常規類型,方法是使用強制轉換來顯式轉換或者通過使用 Value 屬性來轉換。從普通類型到可以為 null 的類型的轉換是隱式的。例如:

復制代碼 代碼如下:

int? a = 5;//int--->int?
double? b = a; //int?---->double?
int? c = (int?)b;//double?---int?
int d = (int)c;//int?---->int  不能隱式轉換例如int d=c;則不能編譯
int? e = null;
int f = e.Value;//可以編譯但是會提示異常引發 InvalidOperationException

可空類型還可以使用預定義的一元和二元運算符(提升運算符),以及現有的任何用戶定義的值類型運算符。如果操作數為 null,這些運算符將產生一個 null 值;否則運算符將使用包含的值來計算結果。例如:

復制代碼 代碼如下:

int? a = 10;
int? b = null;
//一元操作符(+ ++  -- = - ! ~)
a++;        //a=11;
//二元操作符(+ - * / % & | ^ << >>) 
a *= 10;   //a=110;
//a = a + b;  //now a is null
//相等性操作符(== !=) 
if (b == null)
{
    b=b.GetValueOrDefault();
}
Console.WriteLine(a.Value);
a = a + b;
/*  if(a == null) ...  
* if(b == null) ...  
* if(a != b) ... */
//比較操作符 
if (a > b)
{
    Console.WriteLine("a>b");
}

下面總結下C#如何對操作符的用法:
  1. 一元操作符(+ ++ - -- ! ~)。如果操作數為null,結果為null。

  2. 二元操作符(+ - * / % | ^ << >>)。兩個操作數中任何一個為null,結果為null。

  3. 相等性操作符(== !=)。如果兩個操作數都為null,兩者相等。如果一個操作數為null,則兩者不相等。如果兩個操作數都不為null,就對值進行比較,判斷它們是否相等。

  4. 比較操作符(< > <= >=)。兩個操作數中任何一個為null,結果為false。如果兩個操作數都不為null,就對值進行比較。

至此我在對上面代碼的a=a+b解釋一下,它實際等價于:

復制代碼 代碼如下:

a = a.HasValue && b.HasValue ? a.Value + b.Value : (int?)null;

在操縱可空實例時,會生成大量代碼,如以下方法:

復制代碼 代碼如下:

privatestaticint? NullableCodeSize(int? a, int? b)
{
    return a + b;
}

編譯這個方法時,編譯器生成的IL代碼等價于以下的C#代碼:
復制代碼 代碼如下:

privatestatic Nullable<int> NullableCodeSize(Nullable<int> a, Nullable<int> b)
{
Nullable<int> nullable1 = a;
Nullable<int> nullable2 = b;
if(!(nullable1.HasValue & nullable2.HasValue))
returnnew Nullable<int>();
else
returnnew Nullable<int>(nullable1.GetValueOrDefault() + nullable2.GetValueOrDefault());
}

??運算

假如左邊的操作數不為null,就返回這個操作數的值。如果左邊的操作數為null,就返回右邊的操作數的值。利用空接合操作符,可方便地設置變量的默認值。空接合操作符的一個好處在于,它既能用于引用類型,也能用于可空值類型。如下所示:

復制代碼 代碼如下:

//===========可空類型=========
int? b =null;
int a = b ??520;
等價于:

//a = b.HasValue ? b.Value : 520
Console.WriteLine(x); //print:"520"
//===========引用類型=========
String s = GetstringValue();
String s= s ??"Unspecified";


等價于:
復制代碼 代碼如下:

//String s = GetstringValue();
//filename = (s != null) ? s : "Unspecified";

裝箱和拆箱轉換

   假定有一個Nullable<int>變量,它被邏輯上設為null。假如將這個變量傳給一個方法,而該方法期望的是一個object,那么必須對這個變量執行裝箱,并將對已裝箱的Nullable<int>的一個引用傳給方法。但并不是一個理想的結果,因為方法現在是作為一個非空的值傳遞的,即使Nullable<int>變量邏輯上包含null值。為解決這個問題,CLR會在對一個可空變量裝箱的時候執行一些特殊代碼,以維護可空類型在表面上的合法地位。

具體地說,當CLR對一個Nullable<T>實例進行裝箱時,它會檢查它是否為null。如果是,CLR實際就不進行任何裝箱操作,并會返回null值。如果可空實例不為null,CLR就從可空實例中取出值,并對其進行裝箱。也就是說,一個值為5的Nullable<int>會裝箱成值為5的一個已裝箱Int32。如下所示:

復制代碼 代碼如下:

//對Nullable<T>進行裝箱,要么返回null,要么返回一個已裝箱的T
int? n =null;
object o = n; //o為null
Console.WriteLine("o is null={0}", o ==null); //"true"

n =5;
o = n; //o引用一個已裝箱的int
Console.WriteLine("o's type={0}", o.GetType()); //"System.Int32"

CLR允許將一個已裝箱的值類型T拆箱為一個T,或者一個Nullable<T>。假如對已裝箱值類型的引用是null,而且要把它拆箱為Nullable<T>,那么CLR會將Nullable<T>的值設為null。以下代碼對這個行為進行了演示:

復制代碼 代碼如下:

//創建一個已裝箱的int
object o =5;

//把它拆箱為一個Nullable<int>和一個int
int? a = (int?)o; //a=5
int b = (int)o; //b=5

//創建初始化為null的一個引用
o =null;

//把它“拆箱”為一個Nullable<int>和一個int
a = (int?)o; //a=null;
b = (int)0; //拋出NullReferenceException

將一個值類型拆箱為值類型的一個可空的版本時,CLR可能必須分配內存。這是極其特殊的一個行為,因為在其他所有情況下,拆箱永遠不會導致內存的分配。原因在于一個已裝箱的值類型不能簡單的拆箱為值類型的可空版本,在已裝箱的值類型中并不包含 hasValue字段,故在拆箱時CLR必須分配一個Nullable< T>對象,以初始化hasValue = true ,value = 值類型值。
調用接口方法

  下面的代碼中,將一個Nullable<int>類型的變量n轉型為一個IComparable<int>,也就是一個接口類型。然而,Nullable<T>不像int那樣實現了IComparable<int>接口。C#編譯器允許這樣的代碼通過編譯,且CLR的校驗器會認為這樣的代碼是可驗證的,從而允許我們使用這種更簡潔的語法:

復制代碼 代碼如下:

int? n =5;
int result = ((IComparable)n).CompareTo(5); //能順利編譯和運行
Console.WriteLine(result);

  如果CLR沒有提供這一特殊支持,那就必須對已拆箱的值類型進行轉型,然后才能轉型成接口以發出調用:
復制代碼 代碼如下:

int result = ((IComparable)(int)n).CompareTo(5);

可以使用 C# typeof 運算符來創建表示可以為 null 的類型的 Type 對象:

復制代碼 代碼如下:

System.Type type = typeof(int?);

還可以使用 System.Reflection 命名空間的類和方法來生成表示可以為 null 的類型的 Type 對象。但是,如果您試圖使用 GetType 方法或 is 運算符在運行時獲得可以為 null 的類型變量的類型信息,得到的結果是表示基礎類型而不是可以為 null 的類型本身的 Type 對象。

如果對可以為 null 的類型調用 GetType,則在該類型被隱式轉換為 Object 時將執行裝箱操作。因此,GetType 總是返回表示基礎類型而不是可以為 null 的類型的 Type 對象。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 阳江市| 安西县| 新安县| 文成县| 竹北市| 常山县| 东阳市| 九江县| 吴江市| 隆林| 托里县| 万安县| 五家渠市| 渝中区| 高州市| 梨树县| 辰溪县| 曲麻莱县| 当涂县| 公安县| 威海市| 佛冈县| 界首市| 通河县| 集贤县| 隆尧县| 西乌珠穆沁旗| 静宁县| 钦州市| 德化县| 临猗县| 师宗县| 奉新县| 鄂尔多斯市| 阿合奇县| 赤城县| 大同县| 卓资县| 朝阳区| 页游| 临泽县|