Operators in C#
Learn how arithmetic, comparison, logical, assignment, and pattern operators work in C#, with runnable Docker examples
Operators are the verbs of any programming language — they transform values, compare them, and combine them into expressions. C# inherits the familiar infix operator set from the C family (so +, -, *, /, ==, && will look immediately recognizable), but as a modern multi-paradigm language it adds quite a bit on top: null-aware operators, pattern matching expressions, range and index operators, and a strongly-typed evaluation model that makes many subtle bugs into compile-time errors.
Because C# is statically and strongly typed, the compiler checks operator types ahead of time. You cannot accidentally add a string to an int and get silent coercion — the operator overload set determines what is legal, and ambiguous cases must be made explicit through casts or conversions. This is a deliberate trade-off: a little more typing in exchange for catching whole categories of bugs before the program ever runs.
In this tutorial we will walk through arithmetic, comparison, logical, bitwise, and assignment operators, then look at some of C#’s more distinctive operators: the null-coalescing ??, the null-conditional ?., the conditional ?:, and pattern matching with is. Each example is a complete, runnable program.
Arithmetic and Assignment Operators
C# supports the standard arithmetic operators (+, -, *, /, %) plus increment (++) and decrement (--). A key gotcha: integer division truncates toward zero, so 7 / 2 is 3, not 3.5. To get a floating-point result, at least one operand must be floating-point.
Compound assignment operators (+=, -=, *=, /=, %=) update a variable in place and return the new value.
Create a file named Program.cs:
| |
Run it:
| |
Expected output:
a + b = 22
a - b = 12
a * b = 85
a / b = 3 (integer division truncates)
a % b = 2 (remainder)
x / y = 3.4 (floating-point division)
counter after += 3: 13
counter after *= 2: 26
post-increment captured 26, pre-increment captured 28, counter is now 28
Comparison and Logical Operators
Comparison operators (==, !=, <, >, <=, >=) return a bool. Logical operators (&&, ||, !) work on booleans and short-circuit — && stops evaluating once it finds a false, and || stops at the first true. The non-short-circuiting forms (& and |) also exist but force both sides to be evaluated.
For reference types, == uses reference equality by default (unless overridden, as string does for value equality).
Create a file named Program.cs:
| |
Run it with the same Docker command shown above. Expected output:
age == 30 : True
age != 18 : True
age >= 21 : True
canDrive = True
canRentCar = False
isRestricted = True
isShortName (with null guard) = False
greeting == echoed : True
Null-Aware, Conditional, and Pattern Operators
This is where modern C# really diverges from the older C family. The null-conditional operator ?. returns null instead of throwing a NullReferenceException when the left side is null. The null-coalescing operator ?? returns its right operand when the left is null, and ??= assigns only if the variable is null. The conditional operator ?: is C#’s ternary expression. And the is operator combined with patterns lets you test type and shape in a single expression.
Create a file named Program.cs:
| |
Run it with the same Docker command. Expected output:
display = (no input)
length = null
userInput after ??= : default value
score 72 -> grade C
value is a positive int: 42
negative int -7
string of length 5
something else
Operator Precedence
When operators are combined, C# evaluates them according to a fixed precedence table — * and / bind tighter than + and -, comparison binds tighter than &&, and && binds tighter than ||. When in doubt, parentheses cost nothing and make intent obvious to the next reader.
| |
Running with Docker
Each example in this tutorial is a complete program. Save it as Program.cs and run it with:
| |
The command preserves your Program.cs, scaffolds a temporary project around it, and runs it. No local .NET SDK required.
Key Concepts
- Integer division truncates toward zero. Use a
double(or cast one operand) when you need a fractional result. - Compound assignments (
+=,-=, etc.) update in place and return the new value — they are expressions, not just statements. - Logical
&&and||short-circuit, which makes them safe for null-guards likeobj != null && obj.Value > 0. stringequality with==compares character contents, not references — unlike most other reference types in C#.?.and??make null-handling expressive and concise;??=assigns only when the target is null.- Pattern matching with
isandswitchexpressions turns type-and-shape checks into single expressions, blending OOP and functional styles. - Operator precedence follows C-family conventions; reach for parentheses when an expression mixes more than two operator families.
- The compiler enforces types on every operator — accidental cross-type arithmetic is a build error, not a silent coercion.
Running Today
All examples can be run using Docker:
docker pull mcr.microsoft.com/dotnet/sdk:9.0
Comments
Loading comments...
Leave a Comment