Skip to content

C# - Operators Precedence

C# - Operator Precedence and Associativity

Section titled “C# - Operator Precedence and Associativity”

In C#, operator precedence determines the order in which operations are performed in an expression with multiple operators. Think of it like the ‘order of operations’ (PEMDAS/BODMAS) from mathematics. Operators with higher precedence are evaluated before operators with lower precedence.

For example, in the expression var result = 10 + 5 * 2;, the multiplication operator * has higher precedence than the addition operator +. Therefore, 5 * 2 is calculated first (yielding 10), and then 10 + 10 is calculated. The final value assigned to result is 20, not 30.

When operators have the same precedence, their associativity determines the order of evaluation. Most operators are left-associative (evaluated from left to right), while a few, like assignment and null-coalescing operators, are right-associative (evaluated from right to left).

The following table lists C# operators from highest to lowest precedence. Operators within the same category have the same precedence level.

PrecedenceCategoryOperatorsAssociativity
1 (Highest)Primaryx.y, f(x), a[i], x?.y, x?[i], x++, x--, new, typeof, sizeofLeft-to-right
2Unary+, -, !, ~, ++x, --x, (T)x, ^ (index from end)Right-to-left
3Range..Left-to-right
4Multiplicative*, /, %Left-to-right
5Additive+, -Left-to-right
6Shift<<, >>, >>> (unsigned right shift)Left-to-right
7Relational & Type-testing<, >, <=, >=, is, asLeft-to-right
8Equality==, !=Left-to-right
9Bitwise AND&Left-to-right
10Bitwise XOR^Left-to-right
11Bitwise OR|Left-to-right
12Logical AND&&Left-to-right
13Logical OR||Left-to-right
14Null-coalescing??Right-to-left
15Conditional (Ternary)?:Right-to-left
16 (Lowest)Assignment & Lambda=, *=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |=, ??=, =>Right-to-left

Example 1: Precedence (Multiplication vs. Addition)

Section titled “Example 1: Precedence (Multiplication vs. Addition)”

The multiplication operator * is evaluated before the addition operator +.

// Modern C# with top-level statements
int result = 10 + 5 * 2; // Evaluates as 10 + (5 * 2)
Console.WriteLine($"Result: {result}"); // Output: Result: 20

Example 2: Using Parentheses to Override Precedence

Section titled “Example 2: Using Parentheses to Override Precedence”

Parentheses () have the highest precedence and can be used to explicitly control the order of evaluation.

int result = (10 + 5) * 2; // Parentheses force addition to be evaluated first
Console.WriteLine($"Result: {result}"); // Output: Result: 30

The assignment operator = is right-associative. The expression is evaluated from right to left.

int a, b, c;
// Right-to-left evaluation: c is assigned 10, then b is assigned the value of c, then a is assigned the value of b.
a = b = c = 10;
Console.WriteLine($"a: {a}, b: {b}, c: {c}"); // Output: a: 10, b: 10, c: 10

Even if you know the precedence rules, your colleagues might not. Using parentheses makes the code’s intent explicitly clear and reduces the cognitive load on the reader. This is a crucial practice for writing maintainable code in a team environment.

Good: var isValid = (user.IsLoggedIn && user.HasPermissions) || user.IsAdmin;

Less Clear: var isValid = user.IsLoggedIn && user.HasPermissions || user.IsAdmin;

Be careful not to mix up the bitwise AND & with the logical AND &&. While both can be used in boolean expressions, && is “short-circuiting”—it won’t evaluate the right-hand side if the left-hand side is false. This is safer and more efficient. The bitwise & will always evaluate both sides.

string name = null;
// This will throw a NullReferenceException because `&` evaluates both sides.
// bool isInvalid = name != null & name.Length > 0;
// This works correctly because `&&` short-circuits.
// If name is null, the second part is never evaluated.
bool isValid = name != null && name.Length > 0;
Console.WriteLine($"Is valid: {isValid}"); // Output: Is valid: False

Q1: Which operators have the highest precedence in C#? Primary operators like parentheses (), member access ., method invocation f(), and array indexing [] have the highest precedence.

Q2: What happens when two operators have the same precedence? Associativity determines the order. For example, * and / have the same precedence and are left-associative, so 100 / 10 * 2 is evaluated as (100 / 10) * 2, which equals 20.

Q3: How can I avoid confusion with operator precedence? The single best way to avoid ambiguity and bugs is to use parentheses () to explicitly group operations. This makes your code self-documenting and easier for everyone to understand.