Easy Learn C#

C# Operators

Introduction to C# Operators

Operators in C# are symbols that perform operations on operands (variables or values). C# provides a rich set of operators that allow you to perform arithmetic, comparison, logical, bitwise, and other operations.

Arithmetic Operators

Arithmetic operators are used to perform common mathematical operations.

Operator Name Description Example Result
+ Addition Adds two operands 5 + 3 8
- Subtraction Subtracts right operand from left operand 5 - 3 2
* Multiplication Multiplies two operands 5 * 3 15
/ Division Divides the left operand by the right operand 15 / 3 5
% Modulus Returns the remainder after division 10 % 3 1
++ Increment Increases the value by 1 int a = 5; a++; a becomes 6
-- Decrement Decreases the value by 1 int a = 5; a--; a becomes 4

Arithmetic Operators Example:


int a = 10;
int b = 3;

int sum = a + b;        // 13
int difference = a - b; // 7
int product = a * b;    // 30
int quotient = a / b;   // 3 (integer division truncates decimal part)
int remainder = a % b;  // 1

int c = 5;
int d = c++;  // d = 5, c = 6 (postfix: assign then increment)
int e = 5;
int f = ++e;  // f = 6, e = 6 (prefix: increment then assign)
                            

Note that when using integer division, the result is always an integer, and any fractional part is truncated (not rounded). If you need to preserve the fractional part, use floating-point types.

The increment and decrement operators can be used in prefix form (++x, --x) or postfix form (x++, x--). In prefix form, the value is incremented or decremented before it's used in the expression, while in postfix form, the original value is used in the expression and then incremented or decremented.

Assignment Operators

Assignment operators are used to assign values to variables.

Operator Description Example Equivalent to
= Simple assignment x = 5 x = 5
+= Add and assign x += 3 x = x + 3
-= Subtract and assign x -= 3 x = x - 3
*= Multiply and assign x *= 3 x = x * 3
/= Divide and assign x /= 3 x = x / 3
%= Modulus and assign x %= 3 x = x % 3
&= Bitwise AND and assign x &= 3 x = x & 3
|= Bitwise OR and assign x |= 3 x = x | 3
^= Bitwise XOR and assign x ^= 3 x = x ^ 3
<<= Left shift and assign x <<= 2 x = x << 2
>>= Right shift and assign x >>= 2 x = x >> 2

Assignment Operators Example:


int x = 10;

x += 5;  // x is now 15 (10 + 5)
x -= 3;  // x is now 12 (15 - 3)
x *= 2;  // x is now 24 (12 * 2)
x /= 4;  // x is now 6 (24 / 4)
x %= 4;  // x is now 2 (6 % 4)

// Compound assignment operators are more concise and often more efficient
// than their expanded forms
                            

Comparison Operators

Comparison operators are used to compare two values. The result of a comparison is always a boolean value (true or false).

Operator Name Description Example Result
== Equal to Checks if operands are equal 5 == 3 false
!= Not equal to Checks if operands are not equal 5 != 3 true
> Greater than Checks if left operand is greater than right 5 > 3 true
< Less than Checks if left operand is less than right 5 < 3 false
>= Greater than or equal to Checks if left operand is greater than or equal to right 5 >= 5 true
<= Less than or equal to Checks if left operand is less than or equal to right 5 <= 3 false

Comparison Operators Example:


int a = 5, b = 10;

bool isEqual = (a == b);           // false
bool isNotEqual = (a != b);        // true
bool isGreater = (a > b);          // false
bool isLess = (a < b);             // true
bool isGreaterOrEqual = (a >= b);  // false
bool isLessOrEqual = (a <= b);     // true

// Comparison operators are commonly used in conditional statements
if (a < b)
{
    Console.WriteLine("a is less than b");
}
                            

When comparing reference types (like objects, strings), the == operator compares references by default, not content. For content comparison of objects, you would typically use the Equals() method or override the == operator.

Logical Operators

Logical operators are used to determine the logic between variables or values.

Operator Name Description Example Result
&& Logical AND Returns true if both statements are true true && false false
|| Logical OR Returns true if one of the statements is true true || false true
! Logical NOT Reverses the result, returns false if the result is true !true false

Logical Operators Example:


bool isAdult = true;
bool hasLicense = false;

bool canDrive = isAdult && hasLicense;  // false (both must be true)
bool isEligible = isAdult || hasLicense;  // true (at least one is true)
bool isMinor = !isAdult;  // false (reverse of isAdult)

// Logical operators are often used in conditional statements
if (isAdult && hasLicense)
{
    Console.WriteLine("You can drive");
}
else
{
    Console.WriteLine("You cannot drive");
}
                            

The && and || operators in C# are short-circuit operators. This means that the second operand is only evaluated if necessary:

  • For &&, if the first operand is false, the second operand is not evaluated (since the result will be false regardless).
  • For ||, if the first operand is true, the second operand is not evaluated (since the result will be true regardless).

Bitwise Operators

Bitwise operators perform operations on binary representations of numeric values.

Operator Name Description Example Result
& Bitwise AND Sets each bit to 1 if both bits are 1 5 & 3 1
| Bitwise OR Sets each bit to 1 if any of the bits is 1 5 | 3 7
^ Bitwise XOR Sets each bit to 1 if only one of the bits is 1 5 ^ 3 6
~ Bitwise NOT Inverts all the bits ~5 -6
<< Left shift Shifts bits left, filling with zeros from the right 5 << 1 10
>> Right shift Shifts bits right, filling with sign bit from the left 5 >> 1 2

Bitwise Operators Example:


/* Understanding binary representation:
   5 in binary is 0101
   3 in binary is 0011 */

// Bitwise AND (&)
int result1 = 5 & 3;   // 0101 & 0011 = 0001 (decimal: 1)

// Bitwise OR (|)
int result2 = 5 | 3;   // 0101 | 0011 = 0111 (decimal: 7)

// Bitwise XOR (^)
int result3 = 5 ^ 3;   // 0101 ^ 0011 = 0110 (decimal: 6)

// Bitwise NOT (~)
int result4 = ~5;      // ~0101 = 1010 (with sign extension: decimal: -6)

// Left shift (<<)
int result5 = 5 << 1;  // 0101 << 1 = 1010 (decimal: 10)

// Right shift (>>)
int result6 = 5 >> 1;  // 0101 >> 1 = 0010 (decimal: 2)
                            

Bitwise operators are often used for:

  • Flag operations (setting, clearing, checking bits)
  • Low-level optimization
  • Working with hardware interfaces
  • Efficient multiplication or division by powers of 2 (using shifts)

Ternary Operator

The ternary operator (? :) is a conditional operator that takes three operands. It's a shorthand for if-else statements.

Ternary Operator Syntax:


// Syntax: condition ? expression1 : expression2
// If condition is true, expression1 is evaluated and becomes the result
// If condition is false, expression2 is evaluated and becomes the result

int age = 20;
string message = (age >= 18) ? "Adult" : "Minor";
Console.WriteLine(message);  // Output: "Adult"

// Equivalent if-else statement:
string message2;
if (age >= 18)
{
    message2 = "Adult";
}
else
{
    message2 = "Minor";
}
                            

The ternary operator is useful for simple conditional assignments. It makes the code more concise but can reduce readability if overused or nested.

Null-related Operators

C# provides special operators for working with nullable types and null values.

Operator Name Description Example
?? Null-coalescing operator Returns the left-hand operand if it isn't null; otherwise returns the right operand result = value ?? defaultValue;
?. Null-conditional operator Returns null if the operand is null; otherwise performs the operation result = object?.Property;
??= Null-coalescing assignment Assigns the right operand only if the left operand is null target ??= defaultValue;

Null-related Operators Example:


// Null-coalescing operator (??)
string name = null;
string displayName = name ?? "Guest";  // If name is null, use "Guest"
Console.WriteLine(displayName);  // Output: "Guest"

// Null-conditional operator (?.)
Person person = null;
int? age = person?.Age;  // No NullReferenceException, age will be null
Console.WriteLine(age);  // Output: nothing (null)

// With actual object
Person john = new Person { Name = "John", Age = 30 };
int? johnsAge = john?.Age;  // johnsAge will be 30
Console.WriteLine(johnsAge);  // Output: 30

// Null-coalescing assignment (??=)
string message = null;
message ??= "Default message";  // Assigns only if message is null
Console.WriteLine(message);  // Output: "Default message"

// Already has a value, won't change
message ??= "New message";
Console.WriteLine(message);  // Output: "Default message" (unchanged)

class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}
                            

Null-related operators help write more concise and safer code when dealing with potentially null values. They help prevent NullReferenceExceptions and reduce the need for repetitive null checks.

Type Testing Operators

Type testing operators help determine the type of an object at runtime.

Operator Description Example
is Checks if an object is of a specific type if (obj is string)
as Converts an object to a specified type, returns null if conversion fails string str = obj as string;
typeof Gets the Type object for a type Type stringType = typeof(string);

Type Testing Operators Example:


// is operator
object obj = "Hello";
if (obj is string)
{
    Console.WriteLine("obj is a string");
    
    // Pattern matching with is (C# 7.0+)
    if (obj is string str)
    {
        Console.WriteLine($"String length: {str.Length}");
    }
}

// as operator
object obj2 = "World";
string str2 = obj2 as string;  // If obj2 is not a string, str2 will be null
if (str2 != null)
{
    Console.WriteLine($"String: {str2}");
}

// Instead of using cast which throws an exception if fails:
// string str3 = (string)obj2;  // Would throw InvalidCastException if obj2 is not a string

// typeof operator
Type stringType = typeof(string);
Console.WriteLine($"Type name: {stringType.Name}");  // Output: "String"
Console.WriteLine($"Is value type: {stringType.IsValueType}");  // Output: "False"
                            

Type testing operators are essential for robust type checking and conversion in C#. They help avoid runtime exceptions by providing safe ways to check and convert types.

Operator Precedence and Associativity

Operators in C# follow a precedence order that determines the order of operations in expressions. When operators have the same precedence, their associativity determines the order of evaluation.

Operator Precedence (from highest to lowest):

  1. Primary operators: x.y, f(x), a[i], x++, x--, new, typeof, checked, unchecked
  2. Unary operators: +, -, !, ~, ++x, --x, (T)x
  3. Multiplicative operators: *, /, %
  4. Additive operators: +, -
  5. Shift operators: <<, >>
  6. Relational operators: <, >, <=, >=, is, as
  7. Equality operators: ==, !=
  8. Bitwise AND: &
  9. Bitwise XOR: ^
  10. Bitwise OR: |
  11. Logical AND: &&
  12. Logical OR: ||
  13. Conditional operator: ?:
  14. Assignment operators: =, +=, -=, etc.

Examples of Precedence:


// Arithmetic precedence
int result = 5 + 3 * 2;  // 3 * 2 is evaluated first, then added to 5
Console.WriteLine(result);  // Output: 11

// Using parentheses to change precedence
int result2 = (5 + 3) * 2;  // 5 + 3 is evaluated first, then multiplied by 2
Console.WriteLine(result2);  // Output: 16

// Complex expression
bool result3 = 10 > 5 && 3 < 7 || 4 == 4;  // Evaluated as: (10 > 5 && 3 < 7) || 4 == 4
Console.WriteLine(result3);  // Output: True
                            

When in doubt about operator precedence, it's a good practice to use parentheses to make your intentions explicit. This improves code readability and prevents unintended behaviors.

Best Practices for Using Operators

  • Use parentheses to make complex expressions more readable and to explicitly define precedence
  • Be cautious with integer division (/) which truncates the result
  • Avoid overly complex expressions; break them down into simpler parts
  • Be careful with side effects in operators like ++ and --
  • Use the null-conditional and null-coalescing operators to write more concise code when dealing with null values
  • Consider potential overflow when working with arithmetic operations on values close to the limits of their data types
  • Use the is operator with pattern matching for more readable type checks