There’s a large collection of operators available in C#.

Many are common to most programming languages and we use them regularly, e.g. arithmetic, relational, logical, and equality operators. Others might not be as generally useful, but can make your code simpler and more efficient in specific scenarios.

The** conditional operator** is a great replacement for simple *if-else* statements used only to assign one or the other value to the same variable.

if (compactMode) { itemsPerRow = 5; } else { itemsPerRow = 3; }

The same result can be achieved using a single expression with the conditional operator.

itemsPerRow = compactMode ? 5 : 3;

This operator is especially convenient when used with simple expressions. Checking if a value is null would be another good example:

middleName = middleName != null ? middleName : "";

In this special case, the **null-coalescing operator** can be used instead.

middleName = middleName ?? "";

Unfortunately, it only works when we want to directly use the value being checked for null. If we want to access one of its members, we still need the conditional operator.

count = list != null ? list.Count : 0;

To simplify such cases, the **null conditional operator** was introduced in C# 6.

count = list?.Count ?? 0;

It allows safe member access. If the left-hand side value is non-null, it accesses the member. Otherwise it just returns null avoiding the NullReferenceException which would be thrown when trying to access a member of a null-valued variable.

Its usage is not restricted to properties. It also works with fields, methods and even index access.

int? firstValue = list?[0];

The null conditional operator is also a great choice for thread-safe invoking of event handlers.

In earlier versions of C#, the event handler had to be stored in a local variable to be safe in multi-threaded scenarios. Otherwise its value could be changed by another thread after it was checked for null but before it was invoked, causing a NullReferenceException.

public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { var handler = PropertyChanged; if (handler != null) { handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); } }

This whole block of code can be replaced with a single line if the null conditional operator is used:

public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); }

The call is still thread-safe, i.e. the generated code evaluates the variable only once. It then keeps the result in a temporary variable so that it cannot be changed afterwards.

**Bitwise operators** are specialized operators for bit manipulation of 32-bit (int and uint) and 64-bit (long and ulong) numeric values. Let’s take advantage of binary literals and digit separators (both were added in C# 7.0) to see how they behave:

int a = 0b00000000_00000000_00000000_00001111; int b = 0b00000000_00000000_00000000_01010101;

The result of the bitwise AND operator will include the bits which are set in both operands.

var and = a & b; // = 0b00000000_00000000_00000000_00000101

The result of the bitwise OR operator will include the bits which are set in at least one operand.

var or = a | b; // = 0b00000000_00000000_00000000_01011111

The result of the bitwise XOR (exclusive or) operator will include the bits which are set in exactly one operand.

var xor = a ^ b; // = 0b00000000_00000000_00000000_01011010

The result of the bitwise complement operator will include the bits which are not set in its (single) operand.

var complement = ~a; // = 0b11111111_11111111_11111111_11110000

The bitwise shift operators shift the bits in the binary representation to the left or to the right by the given number of places.

var shiftLeft = a << 1; // = 0b00000000_00000000_00000000_00011110 var shiftRight = a >> 1; // = 0b00000000_00000000_00000000_00000111

The bits which move past the end, do not wrap around to the other side. Hence, if we shifted any value far enough to the left or to the right, the result will be 0.

var multiShift = 0b00000000_00000000_00000000_00000001; for (int i = 0; i < 32; i++) { multiShift = multiShift << 1; }

However, if we use the second operand to shift the bits by the same number of places in a single step, the result won’t be the same.

var singleShift = 0b1 << 32; // = 0b1

To understand this behavior, we must look at how the operator is defined.

Before shifting the bits, the second operand will be normalized to the bit length of the first operand with the modulo operation, i.e. by calculating the remainder of dividing the second operand by the bit length of the first operand. In our example, the first operand is a 32-bit number, hence 32 % 32 = 0. The number will be shifted left by 0 places, not 32.

The bitwise AND, OR and XOR operators also serve as **logical operators** when applied to bool operands.

var a = true; var b = false; var and = a & b; // = false var or = a | b; // = true var xor = a | b; // = true

Although these AND and OR operators return the same result as the corresponding **conditional operators** (&& and ||), they don’t behave identically. Operators & and | are eager, i.e. they will evaluate both operands even if the result can be determined after evaluating the first operand. Operators && and || are lazy, i.e. they won’t evaluate the second operand when the result can be determined based on the value of the first operand. This can be an important difference when operands are method calls instead of simple variables:

var eager = true | IsOdd(1); // IsOdd will be invoked var lazy = true || IsOdd(1); // IsOdd won't be invoked

All arithmetic and bitwise operators also have a corresponding shorthand **assignment operator** for the case when the calculated value is assigned to the first operand.

a = a + b; // basic syntax a += b; // shorthand syntax

A special case of arithmetic operators is **increment and decrement operators**, which respectively increment or decrement the operand value by 1. They are available in two flavors: prefix and postfix. As the name implies, the former changes the operand before returning its value, while the latter first returns the operand value, and then changes it.

var n = 1; var prefixIncrement = ++n; // = 2, n = 2 var prefixDecrement = --n; // = 1, n = 1 var postfixIncrement = n++; // = 1, n = 2 var postfixDecrement = n--; // = 2, n = 1

All four operators are most commonly used in for loops to change the value of the loop variable.

*This article was technically reviewed by Yacoub Massad.*

*This article has been editorially reviewed by **Suprotim Agarwal.*

C# and .NET have been around for a very long time, but their constant growth means there’s always more to learn.

We at DotNetCurry are very excited to announce **The Absolutely Awesome Book on C# and .NET**. This is a 500 pages concise technical eBook available in PDF, ePub (iPad), and Mobi (Kindle).

Organized around concepts, this Book aims to provide a concise, yet solid foundation in C# and .NET, covering **C# 6.0, C# 7.0 and .NET Core, with chapters on the latest .NET Core 3.0, .NET Standard and C# 8.0 (final release) too**. Use these concepts to deepen your existing knowledge of C# and .NET, to have a solid grasp of the latest in C# and .NET OR to crack your next .NET Interview.

**Click here to Explore the Table of Contents or Download Sample Chapters!**