Skip to content

C# - Miscellaneous Operators

Beyond the standard arithmetic and logical operators, C# provides a powerful set of miscellaneous operators for tasks like type checking, null handling, and conditional assignments. Mastering these operators can make your code more concise, readable, and robust.

OperatorNameDescriptionExample
?:Ternary ConditionalA concise if-else statement.age >= 18 ? "Adult" : "Minor";
??Null-CoalescingReturns the left-hand operand if it’s not null; otherwise, returns the right-hand operand.string name = userInput ?? "Default";
??=Null-Coalescing AssignmentAssigns the right-hand operand to the left-hand operand only if the left-hand is null.myList ??= new List<int>();
isType Check / Pattern MatchingChecks if an object is of a certain type and can assign it to a new variable.if (obj is string s) { ... }
asSafe Type CastConverts an object to a specified type; returns null if the cast fails instead of throwing an exception.var str = obj as string;
typeof()Get Type ObjectReturns the System.Type object for a type.Type t = typeof(int);
sizeof()Get SizeReturns the size in bytes of a value type. Requires an unsafe context.sizeof(int); // returns 4

Use the ternary operator for simple, one-line conditional assignments. It makes the code more compact than a full if-else block.

int temperature = 25;
string weather = temperature > 20 ? "Warm" : "Cold";
Console.WriteLine($"The weather is {weather}."); // Output: The weather is Warm.

These operators are essential for safely handling null values and providing defaults.

// Using '??' to provide a default value
string? nameFromApi = null;
string displayName = nameFromApi ?? "Guest";
Console.WriteLine($"Welcome, {displayName}!"); // Output: Welcome, Guest!
// Using '??=' to initialize a list only if it's null
List<string>? userRoles = null;
userRoles ??= new List<string>();
userRoles.Add("Admin");
Console.WriteLine($"User has {userRoles.Count} role(s)."); // Output: User has 1 role(s).

3. Type Checking and Pattern Matching (is)

Section titled “3. Type Checking and Pattern Matching (is)”

The is operator has evolved into a powerful pattern matching tool. It’s the modern, preferred way to check an object’s type.

void PrintObjectInfo(object obj)
{
// Modern pattern matching with 'is'
if (obj is string s)
{
Console.WriteLine($"It's a string with length: {s.Length}");
}
else if (obj is int i)
{
Console.WriteLine($"It's an integer with value: {i}");
}
else if (obj is null)
{
Console.WriteLine("The object is null.");
}
else
{
Console.WriteLine($"It's an unknown type: {obj.GetType().Name}");
}
}
PrintObjectInfo("Hello C#"); // It's a string with length: 8
PrintObjectInfo(42);
PrintObjectInfo(null);

Use the as operator when you need to attempt a type cast that might fail. It’s safer than a direct cast (TypeName)obj because it won’t throw an InvalidCastException.

object someValue = "This is a string";
object anotherValue = 123;
// Successful cast
string? result1 = someValue as string;
Console.WriteLine($"Result 1: {result1 ?? "Cast failed"}"); // Output: Result 1: This is a string
// Failed cast - returns null
string? result2 = anotherValue as string;
Console.WriteLine($"Result 2: {result2 ?? "Cast failed"}"); // Output: Result 2: Cast failed

C# also supports pointer-related operators for high-performance or interoperability scenarios. These can only be used in an unsafe context and should be avoided in general application code.

  • sizeof(): Returns the size of a value type in bytes. Useful for memory allocation.
  • & (Address-of): Gets the memory address of a variable.
  • * (Pointer-indirection): Declares a pointer or dereferences it to get the value at its address.
Console.WriteLine("Demonstrating 'sizeof' operator:");
// 'sizeof' must be in an unsafe context for some types, but is safe for primitives.
Console.WriteLine($"The size of int is {sizeof(int)} bytes.");
Console.WriteLine($"The size of double is {sizeof(double)} bytes.");

Warning: Writing unsafe code bypasses the safety guarantees of the .NET runtime. Use it only when absolutely necessary and with a deep understanding of memory management.

  • Prefer Pattern Matching (is): For type checking, prefer if (obj is TypeName variable) over using as followed by a null check. It’s more concise and expressive.
  • Embrace Null-Coalescing: Use ?? and ??= to write cleaner, more robust code for handling potential null values. It’s far superior to verbose if (variable == null) checks.
  • Use Ternary for Simplicity: The ?: operator is excellent for simple conditional assignments, but avoid nesting them as it quickly becomes unreadable.
  • Avoid unsafe Code: Only venture into unsafe contexts for performance-critical interop or low-level algorithms, and be sure to isolate that code.