Skip to content

C# - 运算符优先级

在 C# 中,运算符优先级决定了包含多个运算符的表达式中操作的执行顺序。可以将其类比为数学中的“运算顺序”(如 PEMDAS/BODMAS)。优先级较高的运算符会在优先级较低的运算符之前进行求值。

例如,在表达式 var result = 10 + 5 * 2; 中,乘法运算符 * 的优先级高于加法运算符 +。因此,会首先计算 5 * 2(结果为 10),然后再计算 10 + 10。最终赋给 result 的值为 20,而不是 30。

当运算符具有相同的优先级时,它们的结合性决定了求值的顺序。大多数运算符是左结合的(从左到右求值),而少数运算符,如赋值运算符和空值合并运算符,是右结合的(从右到左求值)。

下表列出了 C# 运算符,从最高优先级到最低优先级。同一类别内的运算符具有相同的优先级。

优先级类别运算符结合性
1 (最高)主要运算符x.y, f(x), a[i], x?.y, x?[i], x++, x--, new, typeof, sizeof从左到右
2一元运算符+, -, !, ~, ++x, --x, (T)x, ^ (从末尾索引)从右到左
3范围运算符..从左到右
4乘法运算符*, /, %从左到右
5加法运算符+, -从左到右
6位移运算符<<, >>, >>> (无符号右移)从左到右
7关系与类型测试运算符<, >, <=, >=, is, as从左到右
8相等性运算符==, !=从左到右
9按位与&从左到右
10按位异或^从左到右
11按位或|从左到右
12逻辑与&&从左到右
13逻辑或||从左到右
14空值合并运算符??从右到左
15条件(三元)运算符?:从右到左
16 (最低)赋值与 Lambda 运算符=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=, ??=, =>从右到左

示例 1:优先级(乘法 vs. 加法)

Section titled “示例 1:优先级(乘法 vs. 加法)”

乘法运算符 * 在加法运算符 + 之前进行求值。

// 现代 C# 的顶级语句
int result = 10 + 5 * 2; // 求值顺序为 10 + (5 * 2)
Console.WriteLine($"Result: {result}"); // 输出: Result: 20

括号 () 具有最高的优先级,可用于显式控制求值顺序。

int result = (10 + 5) * 2; // 括号强制加法运算优先执行
Console.WriteLine($"Result: {result}"); // 输出: Result: 30

赋值运算符 = 是右结合的。表达式从右到左进行求值。

int a, b, c;
// 从右到左求值:c 被赋值为 10,然后 b 被赋值为 c 的值,然后 a 被赋值为 b 的值。
a = b = c = 10;
Console.WriteLine($"a: {a}, b: {b}, c: {c}"); // 输出: a: 10, b: 10, c: 10

即使你了解优先级规则,你的同事可能不了解。使用括号可以明确表达代码意图,并减轻读者的认知负担。这在团队环境中是编写可维护代码的关键实践。

推荐用法: var isValid = (user.IsLoggedIn && user.HasPermissions) || user.IsAdmin;

不够清晰: var isValid = user.IsLoggedIn && user.HasPermissions || user.IsAdmin;

小心不要混淆按位与运算符 & 和逻辑与运算符 &&。虽然两者都可用于布尔表达式,但 && 具有“短路”特性——如果左侧为 false,它就不会评估右侧。这更安全也更高效。而按位 & 总是会评估两侧。

string name = null;
// 这将抛出 NullReferenceException,因为 `&` 会评估两侧。
// bool isInvalid = name != null & name.Length > 0;
// 这可以正确工作,因为 `&&` 具有短路特性。
// 如果 name 为 null,则不会评估第二部分。
bool isValid = name != null && name.Length > 0;
Console.WriteLine($"Is valid: {isValid}"); // 输出: Is valid: False

问题 1:在 C# 中,哪些运算符具有最高的优先级? 主要运算符,例如括号 ()、成员访问 .、方法调用 f() 和数组索引 [] 具有最高的优先级。

问题 2:当两个运算符具有相同的优先级时会发生什么? 结合性决定了它们的顺序。例如,* 和 / 具有相同的优先级并且是左结合的,因此 100 / 10 * 2 会被评估为 (100 / 10) * 2,结果为 20。

问题 3:如何避免运算符优先级造成的混淆? 避免歧义和错误的最佳方法是使用括号 () 来显式分组操作。这使你的代码具有自解释性,并且更容易让所有人理解。