Operators

Operators combine values into new values: arithmetic, comparisons, logical tests, assignments and a few C#-specific shortcuts for working with null. This lesson gathers them together and explains the rules for which operator runs first.

Assignment and compound assignment

= stores a value. The compound forms update a variable using its current value:

C#
int points = 10;
points += 5;    // 15
points -= 3;    // 12
points *= 2;    // 24
points /= 5;    // 4  (integer division)
points %= 3;    // 1
Console.WriteLine(points);

string log = "start";
log += " -> step";
Console.WriteLine(log);
Output
1
start -> step

Increment and decrement

++ adds 1 and -- subtracts 1. Placed before the variable (prefix), the new value is used; placed after (postfix), the old value is used and then the variable changes:

C#
int i = 5;
Console.WriteLine(i++);   // prints 5, then i becomes 6
Console.WriteLine(i);
Console.WriteLine(++i);   // i becomes 7, then prints 7
Console.WriteLine(i--);   // prints 7, then i becomes 6
Console.WriteLine(i);
Output
5
6
7
7
6

On a line by itself (count++;) the two forms do the same thing. Avoid using ++ inside larger expressions — it makes code hard to read.

Comparison operators

Comparisons produce a bool:

C#
int a = 7, b = 10;
Console.WriteLine(a == b);   // equal
Console.WriteLine(a != b);   // not equal
Console.WriteLine(a < b);
Console.WriteLine(a >= 7);
Console.WriteLine("apple" == "apple");
Output
False
True
True
True
True

For strings, == compares the text, not whether they're the same object. Note the difference between = (assign) and == (compare); C# won't let you accidentally write if (a = 5), because the result isn't a bool.

Logical operators

OperatorMeaningTrue when
&&andboth sides are true
||orat least one side is true
!notthe operand is false
^exclusive orexactly one side is true
C#
int age = 25;
bool hasLicence = true;
bool isWeekend = false;

Console.WriteLine(age >= 18 && hasLicence);
Console.WriteLine(isWeekend || age > 65);
Console.WriteLine(!isWeekend);
Console.WriteLine(hasLicence ^ isWeekend);
Output
True
False
True
True

Short-circuit evaluation

&& and || stop as soon as the answer is known. If the left side of && is false, the right side never runs. This lets you guard a risky check with a safe one:

C#
int[] scores = [];

if (scores.Length > 0 && scores[0] > 50)
{
    Console.WriteLine("First score passed");
}
else
{
    Console.WriteLine("No passing first score");
}
Output
No passing first score

Without short-circuiting, scores[0] would run on an empty array and crash.

The conditional operator

condition ? a : b picks one of two values. It's an expression, so it can go anywhere a value can:

C#
int stock = 0;
string label = stock > 0 ? "In stock" : "Sold out";
Console.WriteLine(label);

int n = 3;
Console.WriteLine($"{n} item{(n == 1 ? "" : "s")}");
Output
Sold out
3 items

Null operators

C# has operators for dealing with values that might be null. ?? supplies a fallback, ??= assigns only if the variable is null, and ?. calls a member only if the object isn't null. Lesson 43 covers them fully.

C#
string? nickname = null;
Console.WriteLine(nickname ?? "(no nickname)");
Console.WriteLine(nickname?.Length);   // null: prints an empty line

nickname ??= "Sunny";
Console.WriteLine(nickname);
Console.WriteLine(nickname?.Length);
Output
(no nickname)

Sunny
5

Precedence

When an expression mixes operators, higher-precedence operators run first: multiplication before addition, comparison before &&, && before ||. Parentheses override the order — and make your intent clear:

C#
Console.WriteLine(2 + 3 * 4);
Console.WriteLine((2 + 3) * 4);
Console.WriteLine(10 - 4 - 3);        // left to right: (10 - 4) - 3
Console.WriteLine(true || false && false);
Console.WriteLine((true || false) && false);
Output
14
20
3
True
False
Precedence (high to low)Operators
Primaryx.y x?.y f(x) a[i] x++ x--
Unary! -x ++x --x (T)x
Multiplicative* / %
Additive+ -
Comparison< > <= >= is as
Equality== !=
Logical&& then ||
Null-coalescing??
Conditional?:
Assignment= += ??= …

Bitwise operators

&, |, ^, ~, << and >> work on the individual bits of integers. You'll mostly meet them with flag enums (lesson 41):

C#
int a = 0b1100, b = 0b1010;
Console.WriteLine(Convert.ToString(a & b, 2));   // 1000
Console.WriteLine(Convert.ToString(a | b, 2));   // 1110
Console.WriteLine(Convert.ToString(a ^ b, 2));   // 0110
Console.WriteLine(1 << 4);                        // 16
Console.WriteLine(256 >> 2);                      // 64
Output
1000
1110
110
16
64

Try it yourself

A year is a leap year if it's divisible by 4, except century years, which must be divisible by 400. Test a few years.

Try it yourself · Program.cs
Edit the code, copy it into Program.cs and run it with dotnet run Program.cs (.NET 10 or later). How to set up .NET
Output
1900: common
2000: leap
2024: leap
2026: common