按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 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。
下一章利用泛型来介绍集合类。