Operators
Concept
+, -, *, /, %. Integer division truncates (7 / 2 is 3); if either operand is floating point the result is floating point. % is the remainder and takes the sign of the dividend (-7 % 3 is -1). + also concatenates strings.
==, !=, >, <, >=, <= produce bool. For reference types == compares references unless the type overloads it (string compares contents).
&& (and) and || (or) short-circuit: the right side is evaluated only if needed. ! negates. &, | and ^ on bool evaluate both sides (^ is exclusive or).
Bitwise and Shift On integers: & (and), | (or), ^ (xor), ~ (complement), << (left shift), >> (arithmetic right shift — keeps the sign), >>> (unsigned right shift, C# 11 — fills with zeros). Binary literals (0b1010) and digit separators (1_000_000) make bit work readable.
=, and compound forms +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=, >>>=.
Increment / Decrement x++ returns the old value then increments; ++x increments then returns the new value. The same for --.
a if not null, otherwise b assign b to a only if a is null member access that yields null if a is null element access that yields null if a is null
condition ? whenTrue : whenFalse is an expression — both branches must have compatible types.
Precedence (high → low, abridged)
x.y f(x) a[i] x++ x-- new typeof checked
+x -x !x ~x ++x --x (T)x await
* / %
+ -
<< >> >>>
< > <= >= is as
== !=
& ^ |
&& ||
??
?:
= += -= ... ??= =>Why It Matters
Operators are in every line of code. Integer division, short-circuit evaluation, bit masking (for hardware registers and protocol fields) and null handling are frequent sources of both bugs and interview questions.
Syntax
result = a + b * c; // precedence: * before +
bool ok = a > 0 && b / a > 2; // short-circuit protects the division
int bits = value & 0x0F; // mask the low nibble
string s = input ?? "default";Example
// Arithmetic
Console.WriteLine($"7 / 2 = {7 / 2}, 7 / 2.0 = {7 / 2.0}, 7 % 3 = {7 % 3}, -7 % 3 = {-7 % 3}, 7.5 % 2 = {7.5 % 2}");
Console.WriteLine($"2 + 3 * 4 = {2 + 3 * 4}, (2 + 3) * 4 = {(2 + 3) * 4}");
// Comparison and logical (with short-circuit)
int rpm = 3000;
Console.WriteLine($"rpm > 2500 && rpm < 6000 = {rpm > 2500 && rpm < 6000}, rpm == 3000 || Fail() = {rpm == 3000 || Fail()}");
Console.WriteLine($"!true = {!true}, true ^ true = {true ^ true}");
// Bitwise and shifts
int flags = 0b_1010;
Console.WriteLine($"0b1010 & 0b0110 = {Convert.ToString(flags & 0b0110, 2)}, | = {Convert.ToString(flags | 0b0110, 2)}, ^ = {Convert.ToString(flags ^ 0b0110, 2)}, ~0 = {~0}");
Console.WriteLine($"1 << 4 = {1 << 4}, -16 >> 2 = {-16 >> 2}, -16 >>> 28 = {-16 >>> 28}");
// Assignment and compound assignment
int x = 10;
x += 5; x -= 3; x *= 2; x /= 4; x %= 4;
int mask = 0b1111;
mask &= 0b1100; mask |= 0b0001; mask ^= 0b1000; mask <<= 1; mask >>= 2;
Console.WriteLine($"x = {x}, mask = {Convert.ToString(mask, 2)}");
// Increment / decrement: prefix vs postfix
int i = 5;
int a = i++; // a gets 5, then i becomes 6
int b = ++i; // i becomes 7, then b gets 7
Console.WriteLine($"a = {a},
…Expected Result
rpm == 3000 || Fail() never calls Fail() because the left side is already true. -16 >> 2 keeps the sign (-4), while -16 >>> 28 shifts in zeros (15).
7 / 2 = 3, 7 / 2.0 = 3.5, 7 % 3 = 1, -7 % 3 = -1, 7.5 % 2 = 1.5
2 + 3 * 4 = 14, (2 + 3) * 4 = 20
rpm > 2500 && rpm < 6000 = True, rpm == 3000 || Fail() = True
!true = False, true ^ true = False
0b1010 & 0b0110 = 10, | = 1110, ^ = 1100, ~0 = -1
1 << 4 = 16, -16 >> 2 = -4, -16 >>> 28 = 15
x = 2, mask = 10
a = 5, b = 7, i = 7, i-- = 7, now i = 6
display = unknown, length = null, model = Aurora, first = null
age 17 -> MinorCommon Mistakes
Expecting 5 / 2 to be 2.5 — write 5 / 2.0 or cast.
Using & instead of && and evaluating a side effect or null dereference anyway.
Confusing x++ and ++x inside larger expressions — keep increments on their own line.
Forgetting precedence: a & b == c means a & (b == c); add parentheses.
Comparing strings with == in languages where it compares references — in C# == on string compares contents, but on object it compares references.
Best Practices
Use parentheses whenever precedence is not obvious to a reader.
Prefer ?? and ?. to nested null checks.
Use named constants and binary literals for bit masks (const byte ErrorBit = 0b1000_0000;).
Avoid clever expressions with multiple side effects.
Interview Relevance
Medium–high: x++ vs ++x, short-circuiting, ?? vs ?:, integer division, and bit manipulation ("check whether the 3rd bit is set").
Practice Questions
Compute the average of 3, 4 and 4 as a double correctly.
Test whether bit 5 of a byte is set, then set it, clear it and toggle it.
Rewrite if (name != null) len = name.Length; else len = 0; with null operators.
What is -17 / 5 and -17 % 5? Check with code.
Swap two integers using XOR only.
Quick Quiz
Q1. (Predict the output) int i = 5; int a = i++; int b = ++i; Console.WriteLine($"{a} {b} {i}"); Answer: 5 7 7 (verified).
Q2. (Predict the output) Console.WriteLine(-7 % 3); Answer: -1 — the remainder has the sign of the dividend (verified).
Q3. (Multiple choice) Which operator assigns only when the variable is null? A) ?? B) ?. C) ??= D) ?: Answer: C.
Q4. (Find the bug) if (list != null & list.Count > 0) crashes when list is null. Why?
Answer: & evaluates both sides; use && so list.Count is skipped when list is null (or list is { Count: > 0 }).
Coding Challenge
Given a 16-bit CAN signal word, extract bits 4–9 (6 bits) as an unsigned value.
ushort word = 0b_1010_1101_1011_0110;
int field = (word >> 4) & 0b11_1111; // shift down, then mask 6 bits
Console.WriteLine(Convert.ToString(field, 2).PadLeft(6, '0'));