表达式和运算符
6.1 表达式
运算符是一个符号,它表示返回单个结果的操作。操作数(operand)是指作为运算符输入的数据元素。一个运算符会:
● 将操作数作为输入
● 执行某个操作
● 基于该操作返回一个值
表达式是运算符和操作数的字符串。可以作为操作数的结构有:
● 字面量
● 常量
● 变量
● 方法调用
● 元素访问器,如数组访问器和索引器
● 其他表达式
6.2 字面量
字面量(literal)是源代码中键入的数字或字符串,表示一个指定类型的明确的、固定的值
预定义类型有自己的字面量形式
◾ bool有两个字面量:true 和 false
◾ 对于引用类型变量,字面量 null 表示变量没有设置为内存中的数据
6.2.1 整数字面量
整数字面量是最常见的字面量(一般为十进制数字序列)
◾ 没有小数点
◾ 带有可选的后缀,指明整数的类型
整数类型字面量还可以写成十六进制(hex)形式,数字必须是十六进制数(从0到F),而且字符串必须以0x
或0X
开始(数字0,字母x)
6.2.2 实数字面量
实数字面量的组成如下:
◾ 十进制数字
◾ 一个可选的小数点
◾ 一个可选的指数部分
◾ 一个可选的后缀
格式:【十进制数字
.
十进制数字
指数(e±xx)
后缀
】
实数字面量的后缀:
后缀 | 实数类型 |
---|---|
无、D、d | double |
F、f | float |
M、m | decimal |
6.2.3 字符字面量
字符字面量有两个单引号内的字符组成,字符字面量可以是下面任意一种:单个字符、一个简单转义序列、一个十六进制转义序列或一个Unicode转义序列
◾ 字符字面量的类型是char
◾ 简单转义序列是一个反斜杠后面跟着单个字符
◾ 十六进制转义序列是一个反斜杠,后面跟着一个大写或小写的x,后面再跟着4个十六进制数字
◾ Unicode转义序列是一个反斜杠,后而跟着一个大写或小写的u,后面再跟着4个十六进制数字
重要的特殊字符
名称 | 转义序列 | 十六进制编码 |
---|---|---|
空字符 | \o | 0x0000 |
警告 | \a | 0x0007 |
退格符 | \b | 0x0008 |
水平制表符 | \t | 0x0009 |
换行符 | \n | 0x000A |
重直制表符 | \v | 0x000B |
换页符 | \f | 0x000C |
回车符 | \r | Ox000D |
双引号 | \" | 0x0022 |
单引号 | \’ | 0x0027 |
反斜杠 | |0x005C |
6.2.4 字符串字面量
字符串字面量使用双引号标记,不同于字符字面量使用单引号
有两种字符串字面量类型:
◾ 常规字符串字面量
◾ 逐字字符串字面量
常规字符串申字面量由双引号内的字符序列组成。规则字符串字面量可以包含:
◾ 字符
◾ 简单转义序列
◾ 十六进制和Unicode转义序列
逐字字符串字面量的书写如同常规字符串字面量,但它以一个@字符为前缀。逐字字符串字面量有以下重要特征:
◾ 逐字字面量与常规字符串字面量区别在于转义字符串不会被求值。在双引号中间的所有内容,包括通常被认为是转义序列的内容,都被严格按字符串中列出的那样打印
◾ 逐字字面量的唯一例外是相邻的双引号组,它们被解释为单个双引号字符
6.3 求值顺序
表达式可以由许多嵌套的子表达式构成,子表达式的求值顺序可以使表达式的最终值发生差别
运算符优先级:从高到低
分类 | 运算符 |
---|---|
初级运算符 | a.x 、f(x) 、a[x] 、x++ 、x-- 、new 、typeof 、checked 、unchecked |
一级运算符 | + 、- 、! 、++x 、--x 、(T)x |
乘法 | * 、/ 、% |
加法 | + 、- |
移位 | << 、>> |
关系和类型 | < 、> 、<= 、>= 、is 、as |
相等 | == 、!= |
位与 | & |
位异 | ^ |
位异或 | ` |
条件与 | && |
条件或 | ` |
条件选择 | ?: |
赋值运算符 | = 、*= 、/= 、%= 、+= 、-= 、<<= 、>>= 、&= 、^= 、` |
6.4 简单算术运算符
简单算术运算符执行基本的四则运算
运算符 | 名 称 | 描 述 |
---|---|---|
+ | 加 | 计算两个操作数的和 |
- | 减 | 从第一个操作数中减去第二个操作数 |
* | 乘 | 求两个操作数的乘积 |
/ | 除 | 用第二个操作数除第一个。整数除法,裁取整数部分到最近的整数 |
6.5 求余运算符
求余运算符(%)
用第二个操作数除第一个操作数,忽略掉商,并返回余数
运算符 | 名 称 | 描 述 |
---|---|---|
% | 求余 | 用第二个操作数除第一个操作数并返回余数 |
6.6 关系比较运算符和相等比较运算符
关系比较运算符和相等比较运算符是二元运算符,比较它们的操作数并返回bool
型值
运算符 | 名 称 | 描 述 |
---|---|---|
< | 小于 | 如果第一个操作数小于第二个操作数,返回true,否则返回false |
|大于| 如果第一个操作数大于第二个操作数,返回true,否则返回false
<=|小于等于 |如果第一个操作数小于等于第二个操作数,返回true,否则返回false
=|大于等于 |如果第一个操作数大于等于第二个操作数,返回true,否则返回false
==|等于| 如果第一个操作数等于第二个操作数,返回true,否则返回false
!=|不等于| 如果第一个操作数不等于第二个操作数,返回true,否则返回false
C#中数字不具有bool
意义
比较操作和相等性操作
对于大多数引用类型来说,比较它们的相等性时,将只比较它们的引用
◾ 如果引用相等,也就是说,如果它们指向内存中相同对象,那么相等性比较为true,否则为false,即使内存中两个分离的对象在所有其他方面都完全相等
◾ 这称为浅比较
string类型对象也是引用类型,但它的比较方式不同。比较字符串的相等性时,将比较它们的长度和内容(区分大小写)
◾ 如果两个字符串有相同的长度和内容(区分大小写),那么相等性比较返回true,即使它们占用不同的内存区域
◾ 这称为深比较(deep comparison)
6.7 递增运算符和递减运算符
运算符 | 名 称 | 描 述 |
---|---|---|
++ | 前置递增++ var | 变量的值加1并保存 返回变量的新值 |
++ | 后置递增var++ | 变量的值加1并保存 返回变量递增之前的旧值 |
-- | 前置递减-- var | 变量的值减1并保存 返回变量的新值 |
-- | 后置逆减var-- | 变量的值减1并保存 返回变量递减之前的旧值 |
◾ 无论运算符使用前置形式还是后置形式,在语句执行之后,最终存放在操作数的变量中的值是相同的 | ||
◾ 唯一不同的是运算符返回给表达式的值 |
6.8 条件逻辑运算符
逻辑运算符用于比较或否定它们的操作数的逻辑值,并返回结果逻辑值
逻辑与(AND)和逻辑或(OR)运算符是二元左结合运算符。逻辑非(NOT)是一元运算符
运算符 | 名 称 | 描 述 |
---|---|---|
&& | 与 | 如果两个操作数都是true,结果为true;否则为false |
` | ` | |
! | 非 | 如果操作数是false,结果为true;否则为false |
6.9 逻辑运算符
按位逻辑运算符常用于设置位组(bit pattem)的方法参数
这些运算符,除按位非运算符以外,都是二元左结合运算符,按位非是一元运算符
运算符 | 名 称 | 描 述 |
---|---|---|
& | 位与 | 产生两个操作数的按位与。仅当两个操作位都为1时结果位才是1 |
` | ` | 位或 |
^ | 位异或 | 产生两个操作数的按位异或。仅当一个而不是两个操作数为1时结果位为1 |
~ | 位非 | 操作数的每个位都取反。该操作得到操作数的二进制反码(数字的反码是其二进制形式按位取反的结果。也就是说,每个0都变成1,每个1都变成0) |
二元按位运算符比较它的两个操作数中每个位置的相应位,并依据逻辑操作设置返回值中的位
6.10 移位运算符
按位移位运算符向左或向右把位组移动指定数量个位置,空出的位用0或1填充
移位运算符是二元左结合运算符
运算符 | 名 称 | 描 述 |
---|---|---|
<< | 左移 | 将位组向左移动给定数日个位置。位从左边移出井丢失。右边打开的位位置用0填充 |
>> | 右移 | 将位组向右移动给定数目个位置。位从右边移出并丢失 |
6.11 赋值运算符
赋值运算符对运算符右边的表达式求值,并用该值设置运算符左边的变量表达式的值
赋值运算符是二元右结合运算符
运算符 | 描 述 |
---|---|
= | 简单赋值,计算右边表达式的值,并把返回值赋给左边的变量或表达式 |
*= | 复合赋值,var*=expr 等价于 var = var*(expr) |
/= | 复合赋值,var/=expr 等价于 var = var/(expr) |
%= | 复合赋值,var%=expr 等价于 var = var%(expr) |
+= | 复合赋值,var+=expr 等价于 var = var+(expr) |
-= | 复合赋值,var-=expr 等价于 var = var-(expr) |
<<= | 复合赋值,var<<=expr 等价于 var = var<<(expr) |
>>= | 复合赋值,var>>=expr 等价于 var = var>>(expr) |
&= | 复合赋值,var&=expr 等价于 var = var&(expr) |
^4= | 复合赋值,var^=expr 等价于 var = var^(expr) |
` | =` |
6.12 条件运算符
条件运算符是一种强大且简洁的方法,基于条件的结果,返回两个值之一
条件运算符是三元运算符
运算符 | 名 称 | 描述 |
---|---|---|
?: | 条件运算符 | 对一个表达式求值,并依据表达式是否返回true 或false ,返回两个值之一 |
6.14 用户定义类型转换
可以为自己的类和结构定义隐式转换和显式转换。这允许把用户定义类型的对象转换成某个其他类型,反之亦然
C#提供隐式转换和显式转换
■ 对于隐式转换,当决定在特定上下文中使用特定类型时,如有必要,编译器会自动执行转换
■ 对于显式转换,编译器只在使用显式转换运算符时才执行转换
6.15 运算符重载
C#运算符被定义为使用预定义类型作为操作数来工作。如果面对一个用户定义类型,运算符完全不知道如何处理它。运算符重载允许你定义C#运算符应该如何操作自定义类型的操作数
● 运算符重载只能用于类和结构
● 为类或结构重载一个运算符x,可以声明一个名称为operator x
的方法并实现它的行为(例如:operator +
和operator -
等)
■ 一元运算符的重载方法带一个单独的class或struct类型的参数
■ 二元运算符的重载方法带两个参数,其中至少有一个必须是class或struct类型
public static LimitedInt operator-(LimitedInt x) // Unary
public static LimitedInt operator +(LimitedInt x,double y) // Binary
运算符重载的方法声明:
■ 声明必须同时使用static和public的修饰符
■ 运算符必须是要操作的类或结构的成员
6.15.1 运算符重载的限制
不是所有运算符都能被重载,可以重载的类型也有限制
可重载的一元运算符:
+
、-
、!
、~
、++
、--
、true
、false
可重载的二元运算符:+
、-
、*
、/
、%
、&
、|
、^
、<<
、>>
、==
、!=
、>
、<
、<=
、>=
运算符重载不能做下面的事情:
■ 创建新运算符
■ 改变运算符的语法
■ 重新定义运算符如何处理预定义类型
■ 改变运算符的优先级或结合性
6.16 typeof运算符
typeof运算符返回作为其参数的任何类型的System.Type对象。通过这个对象,可以了解类型的特征。(对任何已知类型,只有一个System.Type对象。)你不能重载typeof运算符
typeof运算符是一元运算符
运算符 | 描述 |
---|---|
typeof | 返回已知类型的System.Type对象 |
6.17 其他运算符
这里不介绍