CLR via C# 学习笔记----Nullable Value Types可以指定为Null的值类型

Nullable Value Types

 

         据你所知,一个值类型的变量不可能是Null的,他统称包含了一个值类型的类型本身。事实上,这就是为什么我们管值类型叫做值类型。不幸的是,有很多情况会有些问题。例如,当你设计这个数据库的类型的时候,可以定义一个列的数据类型是32bit的整型数而对应FCL中的Int32类型。但是,这一列在数据库中暗示着可能为空,就意味着这一列的数据为空是可以接受的。但是使用.NET Framework 来操作数据库中的数据是很困难的因为CLR不允许int32 的值为空的这一种表现形式。

         这有一个Java的例子,java.util.Date类是一个引用类型,因此这个类型可以被置为null.

但是,在CLR中,System.DateTime是一个值类型,DateTime变量是永远不能为空的。如果一个应用程序使用Java来写的并且打算与CLR运行的一个Webservice进行雍熙,那么这里就会有一个问题了。如果Java的应用程序发送一个null因为CLR没有办法呈现并且对它进行操作。

         为了改进这个形式,微软增加了一个Nullable类型的变量在CLR中。为了明白这是怎么工作的,我们现在必须看看FCL中定义的System.Nullable<T>这个类。这里可以逻辑上表现一下System.Nullable<T>类型是如何定义的:

 

   

Code
    [Serializable]
    
public struct Nulllable<T> where T : struct
    {
        
private Boolean hasValue = false;
        
internal T value = default(T);
        
public void Nullable(T value)
        {
            
this.value = value;
            
this.hasValue = true;
        }
        
public Boolean HashValue
        {
            
get { return this.hasValue; }
        }
        
public T Value
        {
            
get
            {
                
if (!hasValue)
                {
                    
throw new InvalidCastException("nullable Object mush have a value");
                }
                
return value;
            }
        }
        
public T GetValueOrDefault()
        {
            
return value;
        }
        
public T GetValueOrDefault(T defaultValue)
        {
            
if (!HashValue)
                
return defaultValue;
            
return value;
        }
        
public override bool Equals(object other)
        {
            
if (!HashValue)
                
return (other == null);
            
if (other == null)
                
return false;
            
return value.Equals(other);
        }
        
public override int GetHashCode()
        {
            
if (!HashValue)
                
return 0;
            
return value.GetHashCode();
        }
        
public override string ToString()
        {
            
if (!HashValue) return "";
            
return value.ToString();
        }
        
public static implicit operator Nullable<T>(T value)
        {
            
return new Nullable<T>(value);
        }
        
public static explicit operator T(Nullable<T> value)
        {
            
return value.Value;
        }

    }
}

 

 

  正如你所见,这个类压缩了值类型的概念同样可以是null。由于Nullable<T>它本身就是一个值类型,它的实体同样是一个轻量级。这就是说,实例同样可以在stack上面,同时实例比初始的值类型加上Boolean类型的大小。注意Nullable类型的变量T,仅限于Struct中,因为引用类型变量可以置为null了。所以现在,如你你想要使用nullavle int32在你的代码中,可以像如下这么写:

  Nullable <Int32> x = 5;

  Nullable <Int32> y = null;

  Cosole.WriteLine(“x:HasValue = {0}, Value={1}”,

           x.HasValue, x.Value);

  Console.WriteLine(“y: HasValue={0},Value={1},

           y.HasValue, y.GetValueOrDefault());

 

C# Support for Nullable Value Types(C#对Nullable类型的支持)

         事实上,C#小组想要整合nullable类型在C#语言中,使他们成为头等公民。其目的就是C# 提供了一个在nullable工作的符号。C#允许代码声明初始化的xy变量是这样被声明的:

  Int32? X = 5;

  Int32? Y = null;

 

C#中,Int32?是一个Nullable<Int32> 的概念。但是C#比这个深入。C#允许你对null类型的转换。如下显示了例子:

         Int32? A = 5;

         Int32? B = null;

   

   

Code
            //一些实际情况。
            Int32? a = 5;
            Int32
? b = null;
            Int32
? c = (Int32)a;
            Double
? d = 5;
            Double
? e = b;
            a
++;//a = 6
            b = -b;//b = null
            a = a + 3// a = 9
            b = b * 3// b = null;
            if (a == null) { } else { }
            
if (b == null) { } else { }
            
if (a != b) { } else { }
            
if (a < b) { } else { }

 

如下显示了一些操作符的计算方式:

l  (+ ++ = == ! ~) 一元的 如果开始null,结果还是null

l  (+ - * / % & | ^ << >>) 二元的,一个是null,另一个也是null

l  ( == !=). =运算符,如果操作数都是null的话,那么他们相等。如果一个是null,那么不想等。如果都不是null,那么比较数值大小再返回是否相等。

l  (< > <= >=)比较运算符,如果一个是null,返回false。如果都不是null,那么比较数值大小。再返回。

 

C# 中的 Null-Coalescing 操作符。

         C#中有一个操作符是这样的(??),需要两个操作数。如果左面的操作数不为null,那么返回左面的操作数。如果左边的操作符为空的话,那么返回右边的操作符。这个(??)操作符非常方便,可以红来设置变量的初始值。    

        

Code
        private static void NullCoalescingOperator()
        {
            Int32
? b = null;
            Int32
? x = b ?? 123;
            Console.WriteLine(x);
            
string temp = GetFilename();
            filename 
= (temp != null? temp : "Untitled";
            
string filename = GetFilename() ?? "Untitled";
        }

 

 

 

CLR Nullable值类型有特殊的支持

 

         CLR的特殊支持提供了装箱,拆箱和GetType,并且调用接口方法,并且这个给Nullable类型使得更适合CRL。对程序员来说会表现的更加的自然,更好的能够接受。

 

  • Nullable类型的装箱

         假想下,Nullable<Int32> 被设置为空,如果这个变量当作方法原型的参数是一个Object传递,那么这个变量必须要装箱。如果一个引用类型被包装成Nullable<Int32>传递给一个方法,这不是一个理想的,因为这个方法需要传递一个非空的,诚然Nullalbe<Int32>变量在逻辑上包含一个null的值。为了修改这个,CLR执行一些特殊的代码当装箱一个非空的变量去说明nullable类型在环境中是一级的公民。

         特别的,当CLR对一个Nullable<T>实例进行装箱的时候,它会检查它是否为空。如果为空的话,CLR事实上不会做任何事情,并且把null返回。如果这个实例不是空的话,那么CLR把这个实例提取出来并且装箱。换句话说就是,一个Nullalbe<Int32>的值是5并且装箱为一个Int32的值。

  Int32? N = null;

  Object o = n;

  Console.WriteLine (“o is null = {0}” ,o == null); //ture

  N = 5;

  O = n;

   Console.WriteLine(“o’s type={0}”, o.GetType()); // System.Int32

 

  • Nullable类型拆箱

 

  Object o = 5;

  Int32? A = (Int32?) o; // a =5

  Int32? B = (Int32) o; //b=5

 

  O = null;

 

  A = (Int32?) o; //a = null

  B = (Int32) o; // NullReferenceException.

posted @ 2009-01-19 16:59  AlexLiu  阅读(1177)  评论(3编辑  收藏  举报