zoukankan      html  css  js  c++  java
  • 可空类型细微见真知!

    ——细微见真知!

    引言

    "??"我很早就知道这它了,但我之前从没想过要拿它出来分享。主要是因为感觉它应该很基础,大家都知道,但是现在我发现身边很多人不知道"??"这个运算符!故有此文,如果您已经对??很熟悉了就没必要看此文了。本文主要内容如下:

    • 1、"??"运算符
    • 2、可空类型
    • 3、深入分析
    • 4、比较

    1、"??"运算符

    如果"??"运算符的左操作数非空,该运算符将返回左操作数,否则返回右操作数。格式如下:

    1 X = A ?? B;

    很明显它是一个二元运算符。如果A不为空的话,X=A;否则X=B。下面我们看一个例子:

     

    01 using System;
    02 using System.Collections.Generic;
    03 using System.Text;
    04  
    05 namespace CsharpTest
    06 {
    07     class Program
    08     {
    09         static void Main(string[] args)
    10         {
    11             int a = 0;
    12             int b = a ?? -1;
    13             System.Console.WriteLine(b);    
    14         }
    15     }
    16 }

     

    你觉得它会输出什么呢?它什么都不会输出,因为会发生编译时错误!会看有如下图所示错误:

    image

    图1、"??"编译时错误

     

    是的,正如提示的那样"??"运算符两边的操作数不能都是int型。这是为何呢?我们来分析一下。这是因为值类型是不可判空的,例如int i可以为i=100,或,0或,或-1,但不可以为i=null。我们再看下面这段代码: 

     

    01 using System;
    02 using System.Collections.Generic;
    03 using System.Text;
    04  
    05 namespace CsharpTest
    06 {
    07     class Program
    08     {
    09         static void Main(string[] args)
    10         {
    11             string a = "yes";//if a=null, then b will equal to "no"
    12             string b = a ?? "no";
    13             System.Console.WriteLine(b);
    14         }
    15     }
    16 }

     

    我们运行这段代码就可以得到输出"yes”(如果a=null,则会输出"no”)。这是因为引用类型可以为null!

    2、可空类型

    那么是不是"??"运算符只能应用在引用类型上呢?或者说我们想应该在值类型上怎么办,例如int?这就要用到可空类型了。可空类型是System.Nullable 结构体的实例。可空类型可以表示其基础值类型正常范围内的值,再加上一个null 值。例如,Nullable<Int32>,读作“可空的Int32”,可以被赋值为-2147483648 到2147483647 之间的任意值,也可以被赋值为null值。Nullable<bool> 可以被赋值为true false,或null。在处理数据库和其他包含可能未赋值的元素的数据类型时,将null赋值给数值类型或布尔型的功能特别有用。例如,数据库中的布尔型字段可以存储值true false,或者该字段也可以未定义。

    但为了简便语法 T? 是System.Nullable<T> 的简写,此处的T 为值类型。这两种形式可以互换。即int?与System.Nullable<int>是等价的。现在我们再看下面的代码: 

     

    01 using System;
    02 using System.Collections.Generic;
    03 using System.Text;
    04  
    05 namespace CsharpTest
    06 {
    07     class Program
    08     {
    09         static void Main(string[] args)
    10         {
    11             int? x = 1;//if x=null, then y will equal to -1. If you don't believe, you can try!
    12             int y = x ?? -1;
    13             System.Console.WriteLine(y);    
    14         }
    15     }
    16 }

     

    这样的我们就可以对int型应用"??"运算符了!上面的代码会输出1。

    可空类型具有以下特性:

    • 可空类型表示可被赋值为 null 值的值类型变量。无法创建基于引用类型的可空类型。(引用类型已支持 null 值。)。

    • 语法 T? 是 System.Nullable<T> 的简写,此处的 T 为值类型。这两种形式可以互换。

    • 为可空类型赋值与为一般值类型赋值的方法相同,如 int? x = 10;  double? d = 4.108;

    • 如果基础类型的值为 null,请使用 System.Nullable.GetValueOrDefault 属性返回该基础类型所赋的值或默认值,例如 int j = x.GetValueOrDefault();

    • 请使用 HasValue  Value 只读属性测试是否为空和检索值,例如 if(x.HasValue) j = x.Value;

      • 如果此变量包含值,则 HasValue 属性返回 True;或者,如果此变量的值为空,则返回 False。

      • 如果已赋值,则 Value 属性返回该值,否则将引发 System.InvalidOperationException

      • 可空类型变量的默认值将 HasValue 设置为 false。未定义 Value

    • 使用 ?? 运算符分配默认值,当前值为空的可空类型被赋值给非空类型时将应用该默认值,如 int? x = null; int y = x ?? -1;

    • 不允许使用嵌套的可空类型。将不编译下面一行:Nullable<Nullable<int>> n;

    3、深入分析

    我们用ildasm查看最后那段代码,知道main函数的IL代码为:

    “??”

    图2、main函数IL代码

    从上面的标号为1的红圈我们可以知道可空类型仍然是值类型。标号为2的红圈即为判断"??"运算符的左操作数是否有值get_HasValue(),接着标号为3的红圈对刚才的返回值进行判断:如果get_HasValue()的返回值为非零 ( true ),则按指定的偏移量分支到目标指令即将返回"??"运算符的左操作数如标号为4的红圈GetValueOrDefault();否则返回右操作数。

    从上图我们可以知道这主要涉及的操作都是System.Nullable 结构体中的方法和属性,get_HasValue为System.Nullable 结构体中的属性而GetValueOrDefault()是System.Nullable 结构体中的方法(请查阅MSDN)。

    如果是用ILDasm查看前面"??"运算符应用于字符串的IL代码,就不会涉及到这些方法和属性,如下图所示:

    ??

    图3、"??"运算符应用于字符串的IL代码

    4、比较

    其实"??"运算符等价于:

    1 if(A!=null)<br>  X = B;<br>else<br>  X = C;

    但是如果用"??"运算符却简便一些,如判断一个id为txtID的TextBox是否为空,如果不空返回它的text;否则生成一个新的TextBox。可以这样写:

    1 string result = ( txtID ?? new TextBox() ).Text;

    还有就是前面提到的可空类型应用于数据库的情况用"??"运算符比较简便。

    "??"运算符是不是也令你先到了"?:"三元运算符呢?"?:"三元运算符的格式如下:

    1 X = A ? B : C;

    这里A是一个布尔表达式,如果A为true则X=A;否则X=C。由于"?:"三元运算符起源于C系的编程语言,大家都比较熟悉了,这里就不深入了。

     

    希望此文给你带来了信息量!

  • 相关阅读:
    AJAX下载,安装及使用(转)
    Vss命令行获取文件
    提升MOSS中运行权限
    数据库还原状态监控(查看事件查看器)
    MOSS常用部署命令stsadm (转)
    Linux系统常用命令
    VSTO Outlook 项目和文件夹的编程示例
    135 、137、139端口等主要用途
    WF编程 InvokeWebServiceActivity
    SQLSERVER2005 建立链接服务器
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/1741875.html
Copyright © 2011-2022 走看看