《c#高级编程(第6版)--第九章》

下载本书

添加书签

c#高级编程(第6版)--第九章- 第4部分


按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!

只有在数据库中,而且把XML数据映射为类型,才不存在这个问题。

这种区别常常令人很头痛,映射数据也要多做许多工作。一种解决方案是把数据库和XML文件中的数字映射为引用类型,因为引用类型可以为空值。但这也会在运行期间带来额外的系统开销。

使用Nullable结构很容易解决这个问题。在下面的例子中,Nullable用Nullable实例化。变量x现在可以像int那样使用了,进行赋值或使用运算符执行一些计算。这是因为我们转换了Nullable类型的运算符。x还可以是空。可以检查Nullable的HasValue和Value属性,如果该属性有一个值,就可以访问该值:

Nullable x;

x = 4;

x += 3;

if (x。HasValue)



   int y = x。Value;



x = null;

因为可空类型使用得非常频繁,所以C#有一种特殊的语法,用于定义这种类型的变量。定义这类变量时,不使用一般结构的语法,而使用?运算符。在下面的例子中,x1和x2都是可空int类型的实例:

Nullable x1;

int? x2;

可空类型可以与null和数字比较,如上所示。这里,x的值与null比较,如果x不是null,就与小于0的值比较:

int? x = GetNullableType();

if (x  null)



Console。WriteLine(〃x is null〃);



else if (x 《 0)



Console。WriteLine(〃x is smaller than 0〃);



可空类型还可以使用算术运算符。变量x3是变量x1和x2的和。如果这两个可空变量中有一个的值是null,它们的和就是null。

int? x1 = GetNullableType();

int? x2 = GetNullableType();

int? x3 = x1 + x2;

提示:

这里调用的GetNullableType()方法只是任意返回可空int的方法的占位符。为了进行测试,可以把它实现为只返回null或返回任意整数值。

非可空类型可以转换为可空类型。从非可空类型转换为可空类型时,在不需要强制类型转换的地方可以进行隐式转换。这种转换总是成功的:

int y1 = 4;

int? x1 = y1;

但从可空类型转换为非可空类型可能会失败。如果可空类型的值是null,把null值赋予非可空类型,就会抛出InvalidOperationException类型的异常。这就是进行显式转换时需要类型转换运算符的原因:

int? x1 = GetNullableType();

int y1 = (int)x1;

如果不进行显式类型转换,还可以使用接合运算符(coalescing operator)从可空类型转换为非可空类型。接合运算符的语法是??,为转换定义了一个默认值,以防可空类型的值是null。这里,如果x1是null,y1的值就是0。

int? x1 = GetNullableType();

int y1 = x1 ?? 0;
9。7。2  EventHandler

在Windows Forms和Web应用程序中,为许多不同的事件处理程序定义了委托。其中一些事件处理程序如下:

public sealed delegate void EventHandler(object sender; EventArgs e);

public sealed delegate void PaintEventHandler(object sender; PaintEventArgs e);

public sealed delegate void MouseEventHandler(object sender; MouseEventArgs e);

这些委托的共同点是,第一个参数总是sender,它是事件的起源,第二个参数是包含事件特定信息的类型。

使用新的EventHandler,就不需要为每个事件处理程序定义新委托了。可以看出,第一个参数的定义方式与以前一样,但第二个参数是一个泛型类型TeventArgs。where子句指定TEventArgs的类型必须派生于基类EventArgs。

public sealed delegate void EventHandler(object sender; TEventArgs e)

   where TEventArgs : EventArgs
9。7。3  ArraySegment

结构ArraySegment表示数组的一段。如果需要数组的一部分,就可以使用数组段。在ArraySegment中,包含了数组段的信息(偏移量和元素个数)。

在下面的例子中,变量arr定义为有8个元素的int数组。ArraySegment类型的变量segment用于表示该整数数组的一段。该段用构造函数初始化,在这个构造函数中,传送了该数组、偏移量和元素个数。其中偏移量设置为2,所以从第三个元素开始,元素个数设置为3,所以6是数组段的最后一个元素。

数组段可以用Array属性访问。ArraySegment还有Offset和Count属性,表示定义数组段的初始化了的值。for循环用于迭代数组段。for循环的第一个表达式初始化为迭代开始的偏移量。第二个表达式指定数组段中的元素个数,以确定迭代是否停止。在for循环中,数组段包含的元素用Array属性来访问:

int'' arr = {1; 2; 3; 4; 5; 6; 7; 8};

ArraySegment segment = new ArraySegment(arr; 2; 3);

for (int i = segment。Offset; i 《 segment。Offset + segmentunt; i++)



   Console。WriteLine(segment。Array'i');



在上面的例子中,ArraySegment结构有什么用处?ArraySegment可以作为参数传送给方法。这样,只要一个参数就可以定义数组、偏移量和元素个数,而不是3个参数。

WorkWithSegment()方法把ArraySegment作为参数。在这个方法的实现代码中,Offset、Count和Array属性的用法与以前相同:

void WorkWithSegment(ArraySegment segment)



   for (int i = segment。Offset; i 《 segment。Offset + segmentunt; i++)

   {

      Console。WriteLine(segment。Array'i');

   }



注意:

数组段不复制原数组的元素,但原数组可以通过ArraySegment访问。如果数组段中的元素改变了,这些变化也会反映到原数组中。

9。8  小结

本章介绍了 2。0中一个非常重要的特性:泛型。通过泛型类可以创建独立于类型的类,泛型方法是独立于类型的方法。接口、结构和委托也可以用泛型的方式创建。泛型引入了一种新的编程方式。我们介绍了算法(尤其是操作和谓词)如何用于不同的类,而且它们都是类型安全的。泛型委托可以去除集合中的算法。

 Framework的其他类型包括Nullable、EventHandler和ArraySegment。

下一章利用泛型来介绍集合类。

小提示:按 回车 [Enter] 键 返回书目,按 ← 键 返回上一页, 按 → 键 进入下一页。 赞一下 添加书签加入书架