Skip to content

08-运算符

运算符是编程中的基础工具,用于对变量进行操作。C# 提供了丰富的运算符,涵盖算术运算、逻辑判断、赋值操作、类型检查等。


一、算术运算符

用于执行基本的数学运算。

运算符操作示例结果
+加法5 + 38
-减法10 - 46
*乘法7 * 214
/除法10 / 33(整数)或 3.333(浮点)
%取余10 % 31
csharp
int a = 10, b = 3;
Console.WriteLine(a + b);   // 13
Console.WriteLine(a - b);   // 7
Console.WriteLine(a * b);   // 30
Console.WriteLine(a / b);   // 3(整数除法,截断小数)
Console.WriteLine(a % b);   // 1(余数)

// 浮点除法——保留小数
double x = 10, y = 3;
Console.WriteLine(x / y);   // 3.33333333333333

// 注意:整数除法截断
Console.WriteLine(10 / 3);   // 3
Console.WriteLine(10 / 3.0); // 3.333...(除数是浮点,结果是浮点)

// 取余的常见用途:判断奇偶
bool isEven = (number % 2 == 0);

算术溢出

csharp
int max = int.MaxValue;     // 2,147,483,647
int overflowed = max + 1;   // -2,147,483,648(默认不检查,绕回)

// 使用 checked 检查溢出
checked
{
    // int result = max + 1;  // 抛出 OverflowException
}

二、自增和自减运算符

运算符名称行为示例
++a前置自增先加 1,再使用新值int b = ++a; → a=6, b=6
a++后置自增先使用当前值,再加 1int b = a++; → b=5, a=6
--a前置自减先减 1,再使用新值int b = --a; → a=4, b=4
a--后置自减先使用当前值,再减 1int b = a--; → b=5, a=4
csharp
int a = 5;
Console.WriteLine(++a);  // 6(先加再输出)
Console.WriteLine(a);    // 6

int b = 5;
Console.WriteLine(b++);  // 5(先输出再加)
Console.WriteLine(b);    // 6

三、赋值运算符

运算符示例等价于
=a = 10赋值
+=a += 5a = a + 5
-=a -= 3a = a - 3
*=a *= 2a = a * 2
/=a /= 2a = a / 2
%=a %= 3a = a % 3
??=a ??= ba = a ?? b
csharp
int x = 10;
x += 5;    // x = 15
x *= 2;    // x = 30
x %= 7;    // x = 2 (30 % 7 = 2)

四、比较运算符

返回 bool 值(truefalse)。

运算符操作示例结果
==等于5 == 5true
!=不等于5 != 3true
>大于10 > 3true
<小于2 < 5true
>=大于等于4 >= 4true
<=小于等于3 <= 4true
csharp
// 值类型的比较:比较值
int a = 10, b = 20;
bool equal = (a == b);       // false
bool greater = (a > b);      // false
bool lessOrEqual = (a <= b); // true

// 引用类型的比较:默认比较引用
string s1 = "Hello";
string s2 = "Hello";
Console.WriteLine(s1 == s2); // true(string 重载了 ==,比较值)

// 引用类型比较引用
object o1 = new object();
object o2 = new object();
Console.WriteLine(o1 == o2); // false(不同对象,不同引用)
Console.WriteLine(o1.Equals(o2)); // false(默认比较引用)

五、逻辑运算符

运算符操作说明示例
&&逻辑与(AND)全部为 true 才为 truea > 0 && b > 0
``逻辑或(OR)
!逻辑非(NOT)取反!(a > 0)
csharp
// 短路求值
bool result1 = (10 > 0) && (10 / 0 == 1);  // ❌ 不会执行到除法

// && 左侧为 false 时,右侧不执行
bool CheckAnd() => true && (true || (0 > 1));

// || 左侧为 true 时,右侧不执行
bool CheckOr() => false && (true || (0 > 1));

// 实际应用:安全检查
if (person != null && person.Age > 18)  // ✅ 先检查 null,避免 NullReferenceException
{
    Console.WriteLine("已成年");
}

逻辑运算符 vs 位运算符

逻辑运算符位运算符区别
&&&&& 短路求值,& 两侧都计算
``

六、位运算符

对整数的二进制位进行操作。

运算符操作示例说明
&按位与5 & 3 → 1 (0101 & 0011 = 0001)都为 1 才为 1
``按位或`5
^按位异或5 ^ 3 → 6 (0101 ^ 0011 = 0110)不同为 1
~按位取反~5 → -6 (~0101 = 1010)1 变 0,0 变 1
<<左移5 << 2 → 20 (0101 << 2 = 10100)相当于乘以 4
>>右移5 >> 2 → 1 (0101 >> 2 = 0001)相当于除以 4
csharp
int a = 5;   // 二进制:0101
int b = 3;   // 二进制:0011

Console.WriteLine(a & b);   // 1  (0001)
Console.WriteLine(a | b);   // 7  (0111)
Console.WriteLine(a ^ b);   // 6  (0110)
Console.WriteLine(~a);      // -6 (1010)
Console.WriteLine(a << 2);  // 20 (左移 2 位 = 乘以 4)
Console.WriteLine(a >> 1);  // 2  (右移 1 位 = 除以 2)

// 位运算的常见用途
// 1. 使用 Flags 枚举(详见 04-常用数据类型)
// 2. 权限检查
bool hasReadPermission = (permission & Permission.Read) != 0;
// 3. 高效乘除 2 的幂
int doubled = value << 1;   // 乘以 2
int halved = value >> 1;    // 除以 2

七、类型测试运算符

运算符说明示例
is检查类型是否匹配obj is string
as安全转换为目标类型obj as string
typeof获取类型的 Type 对象typeof(string)
sizeof获取值类型的大小(字节)sizeof(int)
csharp
// is:类型检查(C# 7.0+ 支持模式匹配)
object obj = "Hello";
if (obj is string s)        // 检查并转换
    Console.WriteLine(s.Length);

// as:安全转换(失败返回 null,不抛异常)
string? text = obj as string;
if (text != null)
    Console.WriteLine(text.Length);

// typeof:获取类型信息
Type type = typeof(string);
Console.WriteLine(type.FullName);  // System.String

// sizeof:获取值类型大小(需在 unsafe 上下文中,或 .NET 6+ 直接使用)
Console.WriteLine(sizeof(int));      // 4
Console.WriteLine(sizeof(double));   // 8
Console.WriteLine(sizeof(decimal));  // 16

八、其他运算符

1. 三元运算符 ? :

csharp
int a = 10, b = 20;
int max = a > b ? a : b;  // 返回较大的值
Console.WriteLine(max);   // 20

2. 空合并运算符 ????=

csharp
string? name = null;
string display = name ?? "默认值";  // name 为 null 时使用默认值

// ??=:左边为 null 时才赋值
name ??= "新值";  // name 为 null,赋值为 "新值"

3. 空条件运算符 ?.?[]

csharp
Person? person = null;
string? city = person?.Address?.City;  // 安全访问链

int[]? arr = null;
int? first = arr?[0];  // null,不抛异常

4. nameof 运算符

获取变量、类型或成员的名称字符串,编译时确定。

csharp
string name = nameof(person);     // "person"
string typeName = nameof(Person); // "Person"
string methodName = nameof(ToString);  // "ToString"
string paramName = nameof(ArgumentException.ParamName);  // "ParamName"

// 典型用途:异常参数名称
void ValidateAge(int age)
{
    if (age < 0)
        throw new ArgumentOutOfRangeException(nameof(age), "年龄不能为负数");
}

// 属性变更通知
public string Name
{
    get => _name;
    set
    {
        _name = value;
        OnPropertyChanged(nameof(Name));  // 重命名属性时,这里会自动更新
    }
}

5. =>(Lambda 运算符)

csharp
// Lambda 表达式
Func<int, int> square = x => x * x;

// 表达式体方法(C# 6.0+)
int Add(int a, int b) => a + b;

// 表达式体属性
string FullName => $"{FirstName} {LastName}";

// 表达式体构造函数
public Person(string name) => Name = name;

6. checked / unchecked

csharp
checked     { int result = int.MaxValue + 1; }  // 抛出异常
unchecked   { int result = int.MaxValue + 1; }  // 允许溢出(默认)

7. await 运算符

csharp
async Task<int> GetDataAsync()
{
    // await 等待异步操作完成
    string result = await httpClient.GetStringAsync(url);
    return result.Length;
}

九、运算符优先级

优先级决定了表达式中运算的执行顺序。优先级高的先执行。

优先级类别运算符
最高基本() [] ?. ?[] ++ -- new typeof sizeof nameof checked unchecked await
1一元+ - ! ~ ++x --x (T)
2乘法* / %
3加法+ -
4移位<< >>
5关系和类型< > <= >= is as
6相等== !=
7位与&
8位异或^
9位或`
10逻辑与&&
11逻辑或`
12空合并??
13三元?:
14赋值和 Lambda= += -= *= /= %= ??= =>
csharp
int result = 5 + 3 * 2;      // 11(乘法优先)
int result = (5 + 3) * 2;    // 16(括号改变优先级)

// 复杂表达式建议加括号,提高可读性
int value = (a > b ? a : b) * 2;  // 比不加括号更清晰

十、运算符重载

允许自定义类型参与运算。

csharp
public struct Vector2
{
    public double X { get; set; }
    public double Y { get; set; }

    // 重载 + 运算符
    public static Vector2 operator +(Vector2 a, Vector2 b)
        => new Vector2 { X = a.X + b.X, Y = a.Y + b.Y };

    // 重载 * 运算符(向量 × 标量)
    public static Vector2 operator *(Vector2 v, double scalar)
        => new Vector2 { X = v.X * scalar, Y = v.Y * scalar };

    // 重载 == 和 !=(通常需要同时重写 Equals 和 GetHashCode)
    public static bool operator ==(Vector2 a, Vector2 b)
        => a.X == b.X && a.Y == b.Y;

    public static bool operator !=(Vector2 a, Vector2 b)
        => !(a == b);

    public override bool Equals(object? obj)
        => obj is Vector2 v && v == this;

    public override int GetHashCode()
        => HashCode.Combine(X, Y);

    public override string ToString() => $"({X}, {Y})";
}

// 使用
var v1 = new Vector2 { X = 1, Y = 2 };
var v2 = new Vector2 { X = 3, Y = 4 };
var sum = v1 + v2;         // (4, 6)
var scaled = v1 * 2.5;     // (2.5, 5)
Console.WriteLine(sum);    // (4, 6)

可重载的运算符

类别可重载的运算符
算术+ - * / %
自增自减++ --
比较== != < > <= >=
位运算& `
不能重载= && `

重载运算符必须是 public static 方法。


核心知识点总结

运算符分类速查

类别运算符
算术+ - * / %
自增自减++ --
赋值= += -= *= /= %= ??=
比较== != < > <= >=
逻辑&& `
位运算& `
类型is as typeof sizeof
空值?? ?. ?[]
其他?: => nameof checked unchecked await new

注意事项

  1. C# 中 = 是赋值,== 是相等判断——不要混淆
  2. 整数除法截断小数——10 / 3 = 3,不是 3.333
  3. 短路求值——&&|| 左侧满足条件时右侧不执行
  4. 优先使用括号——不要依赖优先级记忆,加括号更清晰
  5. is 模式匹配——比 is + 强制转换更安全、更简洁
  6. nameof 编译时确定——重构时自动更新,优于字符串字面量
  7. sizeof 只能用于值类型——引用类型大小不由开发者直接控制
  8. 运算符重载要符合直觉——+ 应该表示相加,不要用于减法等

Released under the MIT License.