17xie > C# 2005 & .NET 3.0高级编程(第5版) > 第6章 运算符和类型强制转换
背景:                 
[本书目录] [图书首页] [本书讨论区]  
链接地址:http://www.17xie.com/read-58489.html    注册17xie 一起来写书 实现您的出书梦想!

前几章介绍了使用C#编写程序所需要的大部分知识。本章将首先讨论基本语言元素,接着论述C#语言的扩展功能。本章的主要内容如下:

C#中的可用运算符

处理引用类型和值类型时相等的含义

基本数据类型之间的数据转换

使用装箱技术把值类型转换为引用类型

通过强制转换技术在引用类型之间转换

重载标准的运算符,以支持对定制类型的操作

给定制类型添加强制转换运算符,以支持无缝的数据类型转换

6.1  运算符

C和C++开发人员应很熟悉大多数C#运算符,这里为新程序员和VB开发人员介绍最重要的运算符,并介绍C#中的一些新变化。

C#支持表6-1所示的运算符,其中有4个运算符(sizeof、*、–>、&)只能用于不安全的代码(这些代码绕过了C#类型安全性的检查),这些不安全的代码见第11章的讨论。

表  6-1

类    别

运  算  符

算术运算符

+ – * / %

逻辑运算符

&  |  ^  ~  &&  ||  !

字符串连接运算符

+

增量和减量运算符

++  – –

移位运算符

<<  >>

比较运算符

==  !=  < >  <=  >=

(续表)   

类    别

运  算  符

赋值运算符

=  += –=  *=  /=  %=  &=  |=  ^=  <<=  >>=

成员访问运算符(用于对象和结构)

.

索引运算符(用于数组和索引器)

[]

数据类型转换运算符

()

条件运算符 (三元运算符)

?:

委托连接和删除运算符(见第7章)

+ –

对象创建运算符

new

类型信息运算符

sizeof (只用于不安全的代码) is typeof as

溢出异常控制运算符

checked unchecked

间接寻址运算符

*  –>  & (只用于不安全代码) []

命名空间别名限定符(见第2章)

::

空接合运算符

??

使用C#运算符的一个最大缺点是,与C风格的语言一样,赋值(=)和比较(==)运算使用不同的运算符。例如,下述语句表示“x等于3”:

x = 3;

如果要比较x和另一个值,就需要使用两个等号(==):

if (x == 3)

{

}

C#非常严格的类型安全规则防止出现常见的C#错误,也就是在逻辑语句中使用赋值运算符代替比较运算符。在C#中,下述语句会产生一个编译错误:

if (x = 3)

{

}

习惯使用宏字符&来连接字符串的VB程序员必须改变这个习惯。在C#中,使用加号+连接字符串,而&表示两个不同整数值的按位AND运算。| 则在两个整数之间执行按位OR运算。VB程序员可能还没有使用过%(取模)运算符,它返回除运算的余数,例如,如果x等于7,则x % 5会返回2。

在C#中很少会用到指针,因此也很少用到间接寻址运算符(–>)。使用它们的唯一场合是在不安全的代码块中,因为只有在此C#才允许使用指针。指针和不安全的代码见第11章。

6.1.1  运算符的简化操作

表6-2列出了C#中的全部简化赋值运算符。

表  6-2

运算符的简化操作

等  价  于

x++, ++x

x = x + 1

x– –,– –x

x = x – 1

x+= y

x = x + y

x–= y

x = x – y

x *= y

x = x * y

x /= y

x = x / y

x %= y

x = x % y

x >>= y

x = x >> y

x <<= y

x = x << y

x &= y

x = x & y

x |= y

x = x | y

x ^= y

x = x ^ y

为什么用两个例子来说明++增量和– –减量运算符?把运算符放在表达式的前面称为前置,把运算符放在表达式的后面称为后置。它们的执行方式有所不同。

增量或减量运算符可以作用于整个表达式,也可以作用于表达式的内部。当x++和++x单独占一行时,它们的作用是相同的,对应于语句x = x + 1。但当它们用于表达式内部时,把运算符放在前面(++x)会在计算表达式之前递增x,换言之,递增了x后,在表达式中使用新值进行计算。而把运算符放在后面(x++)会在计算表达式之后递增x—— 使用x的原值计算表达式。下面的例子使用++增量运算符说明了它们的区别:

int x = 5;

if (++x == 6)

{

   Console.WriteLine("This will execute");

}

if (x++ == 7)

{

   Console.WriteLine("This won't");

}

第一个if条件得到true,因为在计算表达式之前,x从5递增为6。第二个if语句中的条件为false,因为在计算完整个表达式(x=6)后,x才递增为7。

前置运算符– –x和后置运算符x– –与此类似,但它们是递减,而不是递增。

其他简化运算符,如+= 和–=需要两个操作数,用于执行算术、逻辑和按位运算,改变第一个操作数的值。例如,下面两行代码是等价的:

x += 5;

x = x + 5;

6.1.2  三元运算符

三元运算符(?:)是if...else结构的简化形式。其名称的出处是它带有三个操作数。它可以计算一个条件,如果条件为真,就返回一个值;如果条件为假,则返回另一个值。其语法如下:

condition ? true_value : false_value

其中condition是要计算的Boolean型表达式,true_value是condition为true时返回的值,false_value是condition为false时返回的值。

恰当地使用三元运算符,可以使程序非常简洁。它特别适合于给被调用的函数提供两个参数中的一个。使用它可以把Boolean值转换为字符串值true或false。它也很适合于显示正确的单数形式或复数形式,例如:

int x = 1;

string s = x.ToString() + " ";

s += (x == 1 ? "man" : "men");

Console.WriteLine(s);

如果x等于1,这段代码就显示1 man,如果x等于其他数,就显示其正确的复数形式。但要注意,如果结果需要用在不同的语言中,就必须编写更复杂的例程,以考虑到不同语言的不同语法。

6.1.3  checked和unchecked运算符

考虑下面的代码:

byte b = 255;

b++;

Console.WriteLine(b.ToString());

byte数据类型只能包含0~255的数,所以递增b的值会导致溢出。CLR如何处理这个溢出取决于许多方面,包括编译器选项,所以只要有未预料到的溢出风险,就需要用某种方式确保得到我们希望的结果。

为此,C#提供了checked和 unchecked运算符。如果把一个代码块标记为checked,CLR就会执行溢出检查,如果发生溢出,就抛出异常。如果修改代码,使之包含checked运算符:

byte b = 255;

checked

{

   b++;

}

Console.WriteLine(b.ToString());

运行这段代码,就会得到一个错误信息:

Unhandled Exception: System.OverflowException: Arithmetic operation resulted in an overflow.

   at Wrox.ProCSharp.Basics.OverflowTest.Main(String[] args)

注意:

用/checked编译器选项进行编译,就可以检查程序中所有未标记代码中的溢出。

如果要禁止溢出检查,可以把代码标记为unchecked:

byte b = 255;

unchecked

{

   b++;

}

Console.WriteLine(b.ToString());

在本例中,不会抛出异常,但会丢失数据——因为byte数据类型不能包含256,溢出的位会被丢掉,所以b变量得到的值是0。

注意,unchecked是默认值。只有在需要把几个未检查的代码行放在一个明确标记为checked的大代码块中,才需要显式使用unchecked关键字。

6.1.4  is运算符

is运算符可以检查对象是否与特定的类型兼容。例如,要检查变量是否与object类型兼容:

注意:

“兼容”表示对象是该类型,或者派生于该类型。

int i = 10;

if (i is object)

{

   Console.WriteLine("i is an object");

}

int和其他C#数据类型一样,也从object继承而来;表达式i is object将得到true,并显示相应的信息。

6.1.5  as运算符

as运算符用于执行引用类型的显式类型转换。如果要转换的类型与指定的类型兼容,转换就会成功进行;如果类型不兼容,as运算符就会返回值null。如下面的代码所示,如果object引用不指向string实例,把object引用转换为string就会返回null:

object o1 = "Some String";

object o2 = 5;

string s1 = o1 as string;      //s1 = "Some String"

string s2 = o2 as string;     //s1 = null

as运算符允许在一步中进行安全的类型转换,不需要先使用is运算符测试类型,再执行转换。

6.1.6  sizeof运算符

使用sizeof运算符可以确定堆栈中值类型需要的长度(单位是字节):

unsafe

{

   Console.WriteLine(sizeof(int));

}

其结果是显示数字4,因为int有4个字节。

注意,只能在不安全的代码中使用sizeof运算符。第11章将详细论述不安全的代码。

6.1.7  typeof运算符

typeof运算符返回一个表示特定类型的System.Type对象。例如,typeof(string)返回表示System.String类型的Type对象。在使用反射技术动态查找对象的信息时,这个运算符是很有效的。第12章将介绍反射。

6.1.8  可空类型和运算符

对于布尔类型,可以给它指定true或false值。但是,要把该类型的值定义为undefined,该怎么办?此时使用可空类型可以给应用程序提供一个独特的值。如果在程序中使用可空类型,就必须考虑null值在与各种运算符一起使用时的影响。通常可空类型与一元或二元运算符一起使用时,如果其中一个操作数或两个操作数都是null,其结果就是null。例如:

int? a = null;

int? b = a + 4;      // b = null

int? c = a * 5;      // c = null

但是在比较可空类型时,只要有一个操作数是null,比较的结果就是false。即不能因为一个条件是false,就认为该条件的对立面是true,这在使用非可空类型的程序中很常见。例如:

int? a = null;

int? b = -5;

if (a >= b)

   Console.WriteLine("a >= b");

else

   Console.WriteLine("a < b");

注意:

null值的可能性表示,不能随意比较表达式中的可空类型和非可空类型,详见本章后面的内容。

6.1.9  空接合运算符

空接合运算符(??)提供了一种快捷方式,可以在处理可空类型和引用类型时表示Null值。这个运算符放在两个操作数之间,第一个操作数必须是一个可空类型或引用类型,第二个操作数必须与第一个操作数的类型相同,或者可以隐含地转换为第一个操作数的类型。空接合运算符的计算如下:如果第一个操作数不是null,则整个表达式就等于第一个操作数的值。但如果第一个操作数是null,则整个表达式就等于第二个操作数的值。例如:

int? a = null;

int b;

b = a ?? 10;     // b has the value 10

a = 3;

b = a ?? 10;     // b has the value 3

如果第二个操作数不能隐含地转换为第一个操作数的类型,就生成一个编译错误。

6.1.10  运算符的优先级

表6-3显示了C#运算符的优先级。表顶部的运算符有最高的优先级(即在包含多个运算符的表达式中,最先计算该运算符):

表  6-3

运  算  符

初级运算符

() . [] x++ x––  new  typeof  sizeof  checked  unchecked

一元运算符

+  – !  ~  ++x  ––x和数据类型转换

乘/除运算符

*  /  %

加/减运算符

+  –

移位运算符

<<  >>

关系运算符

<  >  <=  >=  is as

比较运算符

= =  !=

按位AND运算符

&

按位XOR运算符

|

按位OR运算符

^

(续表)  

运  算  符

布尔 AND运算符

&&

布尔OR运算符

||

三元运算符

?:

赋值运算符

=  += –=  *=  /=  %=  &=  |=  ^=  <<=  >>=  >>>=

注意:

在复杂的表达式中,应避免利用运算符优先级来生成正确的结果。使用括号指定运算符的执行顺序,可以使代码更整洁,避免出现潜在的冲突。


字数:6978    最后更新:7个月以前 [04-10 21:20]happyskynet 修改
本页编辑者:happyskynet  
[前一页]:5.7 小结  [后一页]:6.2 类型的安全性
[在本页中加入书签] [收藏本书] [推荐本书]
  17xie论坛 > 本书讨论区 > 本页评论   (共0条)
发表评论

用户名称 匿名发表
评论内容
验证码

关于我们 | 版权声明 | 免责声明 | 诚聘英才 | 联系我们 | 合作伙伴 | 友情链接 | 广告合作 | 提交意见
Copyright © 2007 17xie.com 互联网协同写书平台 京ICP备08002671号