什么是表达式?
表达式(expr)是由运算符和操作数组成的。运算符设置对操作数进行什么样的运算。+、-、*、和/等都是运算符,操作数包括文本、常量、变量和表达式等。
什么是运算符?
在C#中提供了多种运算符,运算符是具有运算功能的符号,根据使用运算符的个数,可以将运算符分为单目运算符、双目运算符和三目运算符,其中,单目运算符是作用在一个操作数上的运算符,如正好(+)等;双目运算符是作用在两个操作数上的运算符,如加号(+)、乘法(*)等;三目运算符是作用在三个操作数上的运算符,C#中唯一的三目运算符就是条件运算符(?:)。
基本的算数运算符
C#中的算术运算符是双目运算符,主要包括+、-、*、/和%等5种,他们分别用于进行加、减、乘、除和模(求余数)运算。
运算符 | 说明 | 实例 | 结果 |
+ | 加 | 12.45f+15 | 27.45 |
- | 减 | 4.56-0.16 | 4.4 |
* | 乘 | 5L*12.45f | 62.25 |
/ | 除 | 7/2 | 3.5 |
% | 求余 | 12%10 | 2 |
算数运算符的使用
自增自减运算符
C#中提供了两种特殊的算数运算符:自增、自减运算符,它们分别用++和--表示。
1.自增运算符
++是自增运算符,它是单目运算符。++在使用时有两种形式,分别是++expr和expr++,其中++expr是前置形式,它表示expr自身先加1,其运算结果是自身修改后的值,在参与其他运算;而expr++是后置形式,它也表示自身加1,但其运算结果是自身未修改的值,也就是说expr++是先参见完其他运算,然后再进行自身加1操作。
2.自减运算符
--是自减运算符,它是单目运算符。--在使用时有两种形式,分别是--expr和expr--,其中--expr是前置形式,它表示expr自身先减1,其运算结果是自身修改后的值,在参与其他运算;而expr--是后置形式,它也表示自身减1,但其运算结果是自身未修改的值,也就是说expr--是先参见完其他运算,然后再进行自身减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 |
关系运算符
关系运算符可以实现对两个值的比较运算,关系运算符在完成两个操作数的比较运算之后,会返回一个代表运算结果的布尔值。
关系运算符 | 说明 | 关系运算符 | 说明 | |
== | 等于 | != | 不等于 | |
> | 大于 | >= | 大于等于 | |
< | 小于 | <= | 小于等于 |
逻辑运算符
逻辑运算符是对真和假这两种布尔值进行运算,运算后的结果仍是一个布尔值,C#中的逻辑运算符主要包括&(&&)(逻辑与)、|(||)(逻辑或)、!(逻辑非)。在逻辑运算符中,除了“!”是单目运算符之外,其他都是双目运算符。
运算符 | 含义 | 用法 | 结合方向 |
&&、& | 逻辑与 | op1&&op2 | 左到右 |
||、| | 逻辑或 | op1||op2 | 左到右 |
! | 逻辑非 | !op | 右到左 |
位运算符
位运算符的操作数类型是整型,可以是有符号的也可以是没有符号的。C#中的位运算符有位与、位或、位异或、和位反运算符,其中位与、位或、位异或为双目运算符,取反运算符为单目运算符。位运算是完全针对位方面的操作,因此,它们在实际使用时,需要先将要执行运算的数据转换为二进制,然后才能进行执行运算。
1.”位与“运算
”位与“运算的运算符为“&”,“位与”运算的运算法则是:如果两个整型数据a、b对应位都是1,则结果位才是1,否则为0。如果两个操作数的精度不同,则结果的精度与精度高的操作数相同。
2.“位或”运算
”位或“运算的运算符为“|”,“位或”运算的运算法则是:如果两个操作数对应位都是0,则结果位才是0,否则为1。如果两个操作数的精度不同,则结果的精度与精度高的操作数相同。
3.“位异或”运算
”位异或“运算的运算符为“^”,“位异或”运算的运算法则是:当两个操作数的二进制表示相同(同时为0或同时为1)时,结果为0,否则为1。若两个操作数的精度不同,则结果数的精度与精度高的操作数相同。
4.“取反”运算
”取反“运算也称“按位非”运算,运算符位“~”。“取反”运算就是将操作数对应二进制中的1修改为0,0修改为1。
移位运算符
C#中的移位运算符有两个,分别时左移位<<和右移位>>,这两个运算符都是双目运算符,它们主要用来对整数类型数据进行位移操作。位移运算符的右操作数不可以是负数,并且要小于左操作数的位数。
1.左位移<<运算符
左位移<<运算符是将一个二进制操作数向左移动指定的位数,左边(高位段)溢出的位被丢弃,右边(低位段)的空位用0补充。左移位运算相当于乘以2的n次幂。
2.右位移>>运算符
右位移>>运算符是将一个二进制操作数向右移动指定的位数,右边(低位端)溢出的位被丢弃,而在填充左边(高位端)的空位时,如果高位是0,左移空的位填入0;如果最高位是1,左移空的位填入1。右移位运算相当于除以2的n次幂。
条件运算符
条件运算符用?:表示,它是C#中仅有的一个三目运算符,该运算符需要三个操作数。
其中,判断公式是一个布尔值,可以为真为假,如果判断公式为真,则返回结果1的运算结果,如果判断公式为假,则返回结果2的运算结果。
运算符的优先级与结合性
C#中的表达式是使用运算符连接起来的符合C#规范的式子,运算符的优先级决定了表达式中运算执行的先后顺序。运算符优先级其实相当于进销存的业务流程,如进货、入库‘、销售、出库,只能按这个步骤进行操作。运算符的优先级也是这样的,它是按照一定的先后顺序进行计算的,C#中的运算符优先级由高到低的顺序依次是:
①.自增、自减运算符。
②.算术运算符。
③.移位运算符。
④.关系运算符。
⑤.逻辑运算符。
⑥.条件运算符。
⑦.赋值运算符。
如果两个运算符具有相同的优先级,则会根据其结合性确定是从左到右运算,还是从右到左运算。
运算符类别 | 运算符 | 数目 | 结合性 |
单目运算符 | ++,--,! | 单目 | ← |
算数运算符 | *,/,% | 双目 | → |
+,- | 双目 | → | |
移位运算符 | <<,>> | 双目 | → |
关系运算符 | >,>=,<,<= | 双目 | → |
==,!= | 双目 | → | |
逻辑运算符 | && | 双目 | → |
|| | 双目 | → | |
条件运算符 | ?: | 三木 | ← |
赋值运算符 | =,+=,-=,*=,/=,%= | 双目 | ← |
从表中可以看出,C#中的运算符中,只有单目、条件和赋值运算符的结合性为从右至左,其他运算符的结合性均为从左至右。
表达式中的类型转换
C#中程序对一些不同类型的数据进行操作时,经常用到类型转换,类型转换主要分为隐式类型转换和显式类型转换。
1.隐式类型转换
隐式类型转换就是不需要声明就能进行的转换。进行隐式类型转换时,编译器不需要进行检查就能安全地进行转换。
源类型 | 目标类型 | |||||
sbyte | short、int、long、float、double、decimal | |||||
byte | short、ushort、int、uint、long、ulong、float、double或decimal | |||||
short | int、long、float、double或decimal | |||||
ushort | int、uint、long、ulong、float、double或decimal | |||||
int | long、float、double或decimal | |||||
uint | long、ulong、float、double或decimal | |||||
char | ushort、int、uint、long、ulong、float、double或decimal | |||||
float | double | |||||
ulong | float、double或decimal | |||||
long | float、double或decimal |
从int、uint、long或ulong到float,以及从long或ulong到double的转换可能导致精度损失,但不会影响它的数量级。其他的隐式转换不会丢失任何信息。
2.显示类型转换
显式类型转换也可以称为强制类型转换,它需要在代码中明确地声明要转换的类型。如果在不存在隐式转换的类型之间进行转换,就需要使用显示类型转换。
源类型 | 目标类型 | ||||||
sbyte | byte、ushort、uint、ulong或char | ||||||
byte | sbyte和char | ||||||
short | sbyte、byte、ushort、uint、ulong或char | ||||||
ushort | sbyte、byte、short或char | ||||||
int | sbyte、byte、short、ushort、uint、ulong或char | ||||||
uint | sbyte、byte、short、ushort、in或char | ||||||
char | sbyte、byte或short | ||||||
float | sbyte、byte、short、ushort、int、uint、long、ulong、char或decimal | ||||||
ulong | sbyte、byte、short、ushort、int、uint、long或char | ||||||
long | sbyte、byte、short、ushort、int、uint、ulong或char | ||||||
double | sbyte、byte、short、ushort、int、uint、ulong、long、char或decimal | ||||||
decimal | sbyte、byte、short、ushort、int、uint、ulong、long、char或double |
(1).由于显示类型转换包括所有隐式类型转换和显示类型转换,因此总是可以使用强制转换表达式从任何数值类型转换为任何其他的数值类型。
(2).在进行显示类型转换时,可能会导致溢出错误。
3.装箱
装箱是将值类型隐式转换成object引用类型。
4.拆箱
拆箱是装箱的逆过程,它是将object引用类型显式转换为值类型。
装箱是将一个值类型转换为一个对象类型(object),而拆箱则是将一个对象类型显式转换为一个值类型。对于装箱而言,它是将被装箱的值类型复制一个副本来转换,而拆箱时,需要注意类型的兼容性,例如,不能将一个long类型的的装箱对象拆箱为int类型。