目录
1.运算符
在C#中,运算符是一个符号,它表示返回单个结果的操作。
操作数是值作为运算符输入的数据元素。
在C#中,运算符是用于操作一个或多个操作数的程序元素。
- 接受一个操作数的运算符称为一元运算符(如增量运算符++)
- 接受两个操作数的运算符称为二元运算符(如算术运算符+-/%等)
- 接受三个操作数的运算符称为一三元运算符(只有三目运算符? :)
1.1 运算符定义
1.1.1 算术运算符

1.1.2 求余运算符
第二个操作数除第一个操作数,忽略商,返余数。

1.1.3 关系比较运算符
返回bool型值。

对不同类型关系的比较
- 对于引用类型,对比的是指向的对象是否相同。这种比较方式被称为浅比较。
- 对于string类型,对比的是字符串的长度和内容(区分发小)。这种方式被称为深比较。
- 对于数值表达式,对比的是类型和值。
- 对于enum枚举类型,对比的操作数的实际值。
1.1.4 递增递减操作符
递增递减操作符规则:

递增递减操作符演示:

1.1.5 条件逻辑运算符
逻辑运算符用于比较和否定它们的操作数的逻辑值,并返回结果逻辑值。

逻辑运算符语法: 表达式1 && 表达式2
表达式1 || 表达式2
!表达式1
例子: bool a= (1==1)&&(2==3) //表达式一真一假,返回false
bool b= (1==1) || (3==2) //表达式一阵一家,返回true
注意:条件逻辑运算符使用“短路”(short circuit)模式操作。其含义是:如果计算表达式1之后结果已经确定,那么它会跳过表达式2的求值。由于短路这种行为,导致我们不能在表达式2的位置放置带运算的表达式,因为程序不会计算运算的结果并返回布尔值。
1.1.6 逻辑运算符
按位逻辑运算符常用于设置位组(bite pattern)的方法参数。
下图为逻辑运算符规则,除了 位非 运算符是一元运算符,其他的都为二元运算符。

下为代码段示例:
byte x=12,y=10,z; //byte类型为 8位有符号整形
z=x&y; //z=8
z=x|y; //z=14
z=x^y; //z=6
z=~x; //z=-13
下图为位组操作示例:采用二进制运算

1.1.7 移位运算符
移位运算符将整个位组向左或向右移动指定数目个位置,空出的位按0或1填充。
移位运算符规则:

移位运算符语法: 变量<<移动的位置数
变量>>移动的位置数
底层的硬件使用二进制补码的形式表示有符号二进制数。在二进制补码表达式中,正数无影响;反数则加1。(位组的第一位:正数为0,负数为1)
具体可见下图:

在我们使用移位运算符时,我们结合上面可以发现,左移一位的结果与把它乘2相同、而右移一位则和除2相同。
对于负数而言,右移一位时,最左边用1填充。左移一位时,最右边用0填充。
对于正数,都用0填充。
1.1.8 赋值运算符
赋值运算符规则:

其中复合赋值的含义:
x +=1; //等价于 x=x+1
x *=1; //等价于 x=x*1
x /=1; //等价于 x=x/1
1.1.9 三目运算符
三目运算符是基于条件的结果,返回两个值之一。
三目运算符语法: 数据类型 变量名= 条件表达式?值1:值2;
条件表达式必须返回bool值。
若条件表达式为true,则返回值1。
若条件表达式为false,则返回值2。
三目运算符语法规则:

1.1.10 typeof运算符
typeof为一元运算符,返回作为其参数的任何类型的System.Type对象(对于任何类型,只有一个System.Type对象)。
语法:Type 变量名=typeof(类型名)
FiledInfo[] fi=变量名.GetFields(); //返回类型中包含的变量
MethodInfo[] mi=变量名.GetMethod();//返回类型中包含的方法
1.1.11 nameof运算符
返回用来表示变量、类型或者成员的字符串。
语法:nameof(变量名或类型名或成员名)
示例:
int a=0;
Console.WriteLine(nameof(a)); //打印 “a”
1.2 运算符重载
我们知道,C#运算符的存在是为了使用 预定义类型声明的操作数 进行运算。我们不能将C#运算符应用于用户定义类型。面对这一问题,运算符重载的存在允许我们定义 C#运算符如何操作自定义类型的操作数。
使用运算符重载的要求:
- 运算符重载只能用于类和结构
- 为类或结构重载一个运算符x,可以声明一个名称为 operator x (例如 operator +和operator -等)的方法并实现它的行为
- 一元运算符的重载方法带一个单独的class或struct类型的参数
- public static LimitedInt operator -(LinmitedInt x)
- 二元运算符的重载方法带两个参数,其中至少有一个必须是class或struct类型
- public static LimitedInt operator +(LinmitedInt x,int y)
- 一元运算符的重载方法带一个单独的class或struct类型的参数
(其中operator为关键字)
运算符重载声明的要求:
- 声明必须同时使用 static 和 public 的修饰符
- 运算符必须是要操作的类或结构的成员
运算符示例:
namespace 第八章
{
//用运算符的重载展示LimitedInt的三个运算符重载:负数、减法和加法。
class LimitedInt
{
//const 为关键字,表示此变量为常量,称为常变量。
//常变量值的是用作常量,但本质是变量。
const int MaxValue = 100;
const int MinValue = 0;
public static LimitedInt operator -(LimitedInt x)
{
LimitedInt li=new LimitedInt();
li.TheValue = 0;
return li;
}
public static LimitedInt operator -(LimitedInt x,LimitedInt y)
{
LimitedInt li = new LimitedInt();
li.TheValue = x.TheValue-y.TheValue;
return li;
}
public static LimitedInt operator +(LimitedInt x,float y)
{
LimitedInt li = new LimitedInt();
li.TheValue = x.TheValue + (int)y;
return li;
}
int theValue = 0; //默认为private
//设置属性TheValue的值在0-100之间。
public int TheValue
{
get { return theValue; }
set { theValue = value>MaxValue?MaxValue:value; }
}
}
class 运算符重载
{
static void Main(string[] args)
{
LimitedInt li1= new LimitedInt();
LimitedInt li2= new LimitedInt();
LimitedInt li3= new LimitedInt();
li1.TheValue = 15;
li2.TheValue = 25;
float a = 10;
Console.WriteLine("li1的值为{0},li2的值为{1}",li1.TheValue,li2.TheValue);
li3=-li1;
Console.WriteLine("li3的值为{0}",li3.TheValue);
li3 = li2 - li1;
Console.WriteLine("li3的值为{0}", li3.TheValue);
li3 = li2 + a;
Console.WriteLine("li3的值为{0}", li3.TheValue);
}
}
}
结果示例:

重载运算符的限制:
只有部分运算符能被重载,且有限制。
能被重载的运算符:
- 可重载的一元运算符:+、-、!、~、++、--、true、false
- 可重载的二元运算符:+、-、*、/、%、^、&、<<、>>、<、>、<=、>=
重载运算符的限制:
- 不能创建新的运算符
- 改变运算符的语法
- 重新定义运算符如何处理预定义类型
- 改变运算符的优先级或结合性
- 对于++、--
- 前置++、--
- 在对象上执行递增或递减代码,然后返回对象。
- 后置++、--
- 对于值类型,系统会复制该对象。在对象上执行递增或递减代码,然后返回对象。
- 对于引用类型,会复制引用。在对象上执行递增或递减代码,然后返回对象。
- 复制的引用和原始的引用会指向相同的对象 ,在进行对象上执行递增或递减代码时,保存的引用所指的对象发生了改变。导致返回的是发生变化的对象。
- 前置++、--
2.表达式
表达式是运算符和操作数的字符串。
2.1 字面量
字面量是源代码中键入的数字或字符串。表示一个指定类型的明确的、固定的值。
示例:
Console.WriteLine(“{0}”,111); //111为整数字面量
我们可以看出,字面量是源代码中存在的,所以它们的值可以在编译时可知。
几个预定义类型有自己的字面量:
- bool类型有两个字面量:true 和 false
- 引用类型,字面量为null。(null表示变量没有指向内存中的数据)
2.1.1 整数字面量
整数字面量后缀:
示例:
Console.WriteLine(“{0}”,111); //111为整数字面量
2.1.2 实数字面量
实数字面量后缀:
示例:
Console.WriteLine(“{0}”,124.123); //124.123为double双精度字面量
Console.WriteLine(“{0}”,125.14f); //125.14f为float单精度字面量
2.1.3 字符字面量(转义字符)
2.2 求值顺序
求值顺序表示运算符执行的先后顺序。
我们不必过分追求了解运算符的优先级,在写表达式的过程中一般用( )来改变运算优先级。