1  /  1  页   1 跳转 查看:392

在C#中使用Nullable类型

在C#中使用Nullable类型

C#1.x的版本中,一个值类型变量是不可以被赋予null值的,否则会产生异常。在C#2.0中,微软提供了Nullable类型,允许用它定义包含null值(即空值)的数据类型,这对处理数据库中包含可选字段以及很多方面都有很大帮助。


定义Nullable类型


定义一个nullable类型非常类似于定义一个非nullable类型。不同之处在于使用类型修饰符“?”。比如定义一个整型如下:
int myInt = 1;要使一个整型变量可以存储一个null值,可以如下声明:
int? myNullableInt = 1;这两个变量看起来似乎是一样的。但事实并非如此。实际上,Nullable类型是一个结构体,它有两个公开可读字段:HasValueValueHasValue是一个布尔值,当有值存储时它为真,当变量值为nullHasValue为假。当HavValue为真是时,可以取得变量的值;为假时,当尝试取得变量的值时会抛出一个异常。
现在nullC#的一个关键字,它可以被赋给一个Nullable型变量。下面是对Nullable型变量赋值的两种有效方式。
double? myDouble = 3.14159;double? myOtherDouble = null;可以看到,myDouble被赋给一个值,它也可以被赋以null。在第二个语句中,myOtherDouble被初始化为null——在一个非Nullable型变量中这样做会产生异常。
使用nullable类型
    一个Nullable型变量可以像一般值类型那样使用。在编译过程中Nullable型变量和非Nullable型变量会进行隐式田转换。就是说我们可以把一个标准整型赋给一个整型Nullable变量,反之亦然。参考下面示例代码:
int? nFirst = null;
int
Second = 2; nFirst = Second;
// 可以
nFirst = 123;
// 可以
Second = nFirst;
//也可以,因为此时nFirst==123 nFirst = null;
// 可以
Second = nFirst;
// 抛出异常, Second 是一个非nullable型变量。

    可以看到,只要一个
Nullable型变量的值不是null,它就可以和一个非Nullable型变量交换变量的值。如果包含null值,
就会抛出异常。为避免异常发生,可以利用
Nullable型变量的HasValue属性。 if (nFirst.HasValue) Second = nFirst;
如上所示,如果nFirst 含有一个值,这个赋值语句就会运行;否则,就会跳过。
Nullable值中使用操作符:Lifed Operators【1】
    两个相同类型的Nullable型和非Nullable型变量除了可以相互自动转化之外,还可以通过操作符在它们中进行操作。参考下面代码:
int ValA = 10;
int? ValB = 3;int? ValC = ValA * ValB;
//ValC==30 int ValA = 10;
int? ValB = null;int? ValC = ValA * ValB;
//ValC==null int ValA = 10;
int? ValB = null;int? ValC = ValA + ValB;
//ValC仍然是null;
    可以看到,两个操作数只要有任何一个是null,得到的结果也一定是null,不管是加减还是乘除。当然,如果操作数不是null ,则结果还是按原来操作符运算得到的结果。
在上面的代码中,如果ValC不是Nullable类型,情况会怎么样呢?如以下代码:int ValA = 10;
int? ValB = 3;int ValC = ValA * ValB;
// ValC 不是Nullable类型上面这段代码会抛出一个异常。ValA * ValB的结果是null,它不能被赋给一个非Nullable变量ValC。因为,会产生异常。 关系运算
    两个都是null值的Nullable变量被认为是相等的,而一个值为null的变量和其它任何非null值的变量都是不相等的。如下面示例代码:

int abc = 123;
int xyz = 890;

int? def = null;
int? uvw = 123;

Comparison
Result
abc == xyz
// false
abc == def
// false
def == null
// true

abc == uvw
// true
uvw == null
// false
uvw != null
// true

在其它关系运算中,如果其中一个或两个操作数为null,则结果一定是false。如下面示例代码(仍然使用上面定义的变量): Comparison
Result

abc > uvw
// false, they are equal
abc < def
// false, def is null
uvw < def
// false, because def is null
def > null

// false, because right side is null
uvw > null
// false, because right side is null

移除空值
    C#2.0同时也提供一个新操作符’??’用来合并空值。其语法格式如下:
returnValue = first ?? second;
在这个语句中,如果first为非null,则first的值会被赋给returnValue;如果firstnull,则second会被赋给returnValue注:returnValue可以是Nullable类型也可以是非Nullable类型。 如果要将一个Nullable变量的值赋给一个非Nullable变量,可以用下面方法:
int? ValA= 123;
int? ValB = null;

int NewVarA = ValA ?? -1;
int NewVarB = ValB ?? -1;

上面这段代码运行完以后,NewVarA的值为123,因为ValA的值不是null。而NewVarB值变为 -1,因为ValBnull。这就允许我们利用一个null值将一个变量转变成一个默认值。在上面的代码中,这个默认值为 -1

后记:这几天开始学习.NET2.0C#2.0技术,在Codeguru上面看到这篇文章,本来想把它翻译出来再post到这里,不过翻译了一半就发现有很多专业术语虽然我可以理解它的意思,它却不能用中文正确表达出来,所以就放弃了翻译全文的想法,只是按照自己的理解把文章的意思写出来。有兴趣的朋友可以去看英文原文,其实我发现看英文更加容易理解。 Reference:[1]Lifed Operators为原文词汇,参考:http://www.codeguru.com/Csharp/.NET/net_data/datagrid/article.php/c10393
http://www.Aspx1.Com
请帮忙宣传Aspx1 , Aspx1是ASP.NET学习者的家园 , 适宜长期居住.
 

C# 2.0 - Nullable

本文资料引用自李建忠先生的演讲稿

C# 引入Nullable类型,允许我们将值类型赋值为null。
其实质上是在Framework中增加了一个Nullable<T>的泛型结构类型。
[SerializableAttribute()]
public struct Nullable<T> : IFormattable, IComparable, INullableValue
  where T : ValueType
看看上面的声明,我们可以确定,Nullable是一个值类型,而且限制类型参数为值类型。
另外C#在语法层面作了简化,见下面的代码。
int? x = 3;
Nullable<int> y = new Nullable<int>(3);
看看反编译的结果。
Nullable<int> nullable1 = new Nullable<int>(3);
Nullable<int> nullable2 = new Nullable<int>(3);
实际上,编译器会将缩写方式处理成完整的结构体创建代码。

Nullable包含两个有用的属性,HasValue用来判断类型是否为空,如果不为空则可以通过Value属性获取其基础类型的值。
当其值不为空时,可以直接使用其基础类型的运算符进行操作。GetValueOrDefault 方法可以获取值或者基础类型的缺省值。
int? x = 3;
int y = 1;
Console.WriteLine(x + y);
不过看看这段代码的反编译结果,你可能会发现一些问题。
Nullable<int> nullable1 = new Nullable<int>(3);
int num1 = 1;
Nullable<int> nullable2 = nullable1;
int num2 = num1;
Console.WriteLine(nullable2.get_HasValue() ? new Nullable<int>(nullable2.GetValueOrDefault() + num2) : new Nullable<int>());
原本简单的代码变得很复杂,编译器创建了新的Nullable对象,而且通过判断,如发现Nullable对象为空,则放弃加法操作,直接返回空。
继续看反编译的IL代码,还出现了box指令,因此Nullable类型的代价是很高的,如非必须,不要使用。
.entrypoint
// Code Size: 63 byte(s)
.maxstack 3
.locals init (
[mscorlib]System.Nullable`1<int32> nullable1,
int32 num1,
[mscorlib]System.Nullable`1<int32> nullable2,
int32 num2,
[mscorlib]System.Nullable`1<int32> nullable3)
L_0000: nop
L_0001: ldloca.s nullable1
L_0003: ldc.i4.3
L_0004: call instance void [mscorlib]System.Nullable`1<int32>::.ctor(!0)
L_0009: nop
L_000a: ldc.i4.1
L_000b: stloc.1
L_000c: ldloc.0
L_000d: stloc.2
L_000e: ldloc.1
L_000f: stloc.3
L_0010: ldloca.s nullable2
L_0012: call instance bool [mscorlib]System.Nullable`1<int32>::get_HasValue()
L_0017: brtrue.s L_0025
L_0019: ldloca.s nullable3
L_001b: initobj [mscorlib]System.Nullable`1<int32>
L_0021: ldloc.s nullable3
L_0023: br.s L_0033
L_0025: ldloca.s nullable2
L_0027: call instance !0 [mscorlib]System.Nullable`1<int32>::GetValueOrDefault()
L_002c: ldloc.3
L_002d: add
L_002e: newobj instance void [mscorlib]System.Nullable`1<int32>::.ctor(!0)
L_0033: box [mscorlib]System.Nullable`1<int32>
L_0038: call void [mscorlib]System.Console::WriteLine(object)
L_003d: nop
L_003e: ret
最后提一下 ?? 这个操作符。

The ?? defines a default value that is returned when a nullable type is assigned to a non-nullable type.
// ?? operator example.
int? x = null;
int y = x ?? -1; // Assigns y to -1 if x is null.
http://www.Aspx1.Com
请帮忙宣传Aspx1 , Aspx1是ASP.NET学习者的家园 , 适宜长期居住.
 

用Nullable类型支持DBNull值

通过向变量声明添加(of Type)类型参数,.NET Framework 2.0可向VB.NET 2005添加泛型类型。Nullable变量是泛型类型的扩展,它可以使值类型(Inter、Int16、Decimal、Data、DataTime等)支持空值。将Nothing赋给值类型会返回该类型的默认值:数字类型返回0,日期类型返回01/01/0001 12:00:00。

如果用Nullable(of Type)代替值类型数据类型标识符,可以使空值有效。引用类型(如String)本身支持空值,因此不需要添加Nullable(of String)。Nullable变量的最有用的应用是方法签名。在方法签名中,采用Nullable值类型可避免重载。例如,在Northwind Order表中通过类型化DataSet插入一个新行时,一般需要如下所示的两个Insert方法签名和对应的两个Overload函数。

Function Insert(ByVal CustomerID As String,

                ByVal EmployeeID As Integer, _

                ByVal OrderDate As Date, _

                ByVal RequiredDate As Date, _

                ByVal ShippedDate As Date, _

                ByVal ShipVia As Integer,

                ByVal Freight As Decimal,

                ByVal ShipName As String, _

                ByVal ShipAddress As String,

                ByVal ShipCity As String, _

                ByVal ShipRegion As String,

                ByVal ShipPostalCode As String, _

                ByVal ShipCountry As String) As Integer

   

Function Insert(ByVal CustomerID As Object,

                ByVal EmployeeID As Object, _

                ByVal OrderDate As Object,

                ByVal RequiredDate As Object, _

                ByVal ShippedDate As Object, _

                ByVal ShipVia As Object, _

                ByVal Freight As Object, _

                ByVal ShipName As Object, _

                ByVal ShipAddress As Object, _

                ByVal ShipCity As Object, _

                ByVal ShipRegion As Object, _

                ByVal ShipPostalCode As Object, _

                ByVal ShipCountry As Object) As Integer

如果所有的值均存在,则第一个方法签名有效。如果传递给函数的任一值类型为空,则需要第二个非类型化签名。在这种情况下,用户的代码可提供一个String值来代替Integer值或Decimal值。向值类型添加Nullable(Of Type)后,可以使单个的函数处理空值类型,如下面的代码所示。

Function Insert(ByVal CustomerID As String, _

                ByVal EmployeeID As Nullable(Of Integer), _

                ByVal OrderDate As Nullable(Of Date), _

                ByVal RequiredDate As Nullable(Of Date), _

                ByVal ShippedDate As Nullable(Of Date), _

                ByVal ShipVia As Nullable(Of Integer), _

                ByVal Freight As Nullable(Of Decimal), _

                ByVal ShipName As String, _

                ByVal ShipAddress As String, _

                ByVal ShipCity As String, _

                ByVal ShipRegion As String, _

                ByVal ShipPostalCode As String, _

                ByVal ShipCountry As String) As Integer

设置与Nullable类型对应的INSERT或UPDATE参数值时,需要通过HasValue属性测试指定值是否存在。如果HasValue为True,则传递Value属性,如下面使用INSERT命令的代码段所示。代码中用INSERT命令添加所需要的参数。

...

Me.InsertCommandParameters(0).Value = CustomerID

If EmployeeID.HasValue Then

  Me.InsertCommandParameters(1).Value = EmployeeID.Value

Else

  Me.InsertCommandParameters(1).Value = DBNull.Convert

End If

If OrderDate.HasValue Then

  Me.InsertCommandParameters(2).Value = OrderDate.Value

Else

  Me.InsertCommandParameters(2).Value = DBNull.Convert

End If

If RequiredDate.HasValue Then

  Me.InsertCommandParameters(3).Value = RequiredDate.Value

Else

  Me.InsertCommandParameters(3).Value = DBNull.Convert

End If

If ShippedDate.HasValue Then

  Me.InsertCommandParameters(4).Value = ShippedDate.Value

Else

  Me.InsertCommandParameters(4).Value = DBNull.Convert

End If

...

由于基表外键的约束,不需要为不能为空的变量指定Nullable类型,就如前面示例中的EmployeeID所示。对于承受业务规则的变量也是如此。例如,每一个订单均需要一个OrderData值。
用户还可以将Nullable(Of Type)应用于Public或Private类成员。下面是一个有映射到Northwind Order表字段的Public属性的简单业务对象的示例。通过业务规则和外键约束来决定哪些字段是Nullable。本例为RequiredData、ShippedDate、Freight、ShipRegion以及ShipPostalCode。ShipRegion和ShipPostalCode是引用类型,它们均被定义为Nullable。

Public Class Orders

  Public OrderID As Integer

  Public CustomerID As String

  Public EmployeeID As Integer

  Public OrderDate As Date

  Public RequiredDate As Nullable(Of Date)

  Public ShippedDate As Nullable(Of Date)

  Public ShipVia As Integer

  Public Freight As Nullable(Of Decimal)

  ...

  Public ShipCountry As String

End Class

以下是前面所介绍类的简化形式,它通过Get和Set访问器使用私有成员。

Public Class Orders

  Private m_OrderID As Integer

  Public Property OrderID() As Integer

      Get

        Return m_OrderID

      End Get

      Set(ByVal value As Integer)

        m_OrderID = value

      End Set

  End Property

...

  Private m_RequiredDate As Nullable(Of Date)

  Public Property RequiredDate() As Nullable(Of Date)

      Get

        Return m_RequiredDate

      End Get

      Set(ByVal value As Nullable(Of Date))

        m_RequiredDate = value

      End Set

  End Property

  Private m_ShippedDate As Nullable(Of Date)

  Public Property ShippedDate() As Nullable(Of Date)

      Get

        Return m_ShippedDate

      End Get

      Set(ByVal value As Nullable(Of Date))

        m_ShippedDate = value

      End Set

  End Property

...

  Private m_Freight As Nullable(Of Decimal)

  Public Property Freight() As Nullable(Of Decimal)

      Get

        Return m_Freight

      End Get

      Set(ByVal value As Nullable(Of Decimal))

        m_Freight = value

      End Set

  End Property

...

  Private m_ShipCountry As String

  Public Property ShipCountry() As String

      Get

        Return m_ShipCountry

      End Get

      Set(ByVal value As String)

        m_ShipCountry = value

      End Set

  End Property

End Class

指定Nullable类成员并使用HasValue和Value属性等价于用If ReferenceType Is Noting Then … 或If ValueType=Nothing Then…来测试指定的属性值。示例项目NullableTypes.sln利用由SqlDataReader填充的对象为Order表测试了这两种方法。
http://www.Aspx1.Com
请帮忙宣传Aspx1 , Aspx1是ASP.NET学习者的家园 , 适宜长期居住.
 
1  /  1  页   1 跳转

版权所有 ASP.NET学习门户 2.0.1214   Sitemap  

返顶部