Unity C# Must-Know Operators

Unity is a game engine that does a lot of "heavy-lifting" for developers in terms of functionality and lets them focus entirely on the development process. It utilizes C# as the main programming language.

As with any programming language, C# consists of an array of special functions, types, classes, libraries, etc., but it also has a list of special symbols (operators) that each has its own function. In this post, I will be listing those symbols and will explain what they do, so that the next time you open a script, you would be able to quickly understand what each part means.

Operators in C# are some special symbols that perform some action on operands.

In C#, there are 6 types of built-in operators: Arithmetic operators, Comparison operators, Boolean logical operators, Bitwise and shift operators, Equality operators, and Miscellaneous operators. Knowing all of them will make you instantly a better programmer.

1. Arithmetic operators

The following operators perform arithmetic operations with operands of numeric types:

  • Unary ++ (increment), -- (decrement), + (plus), and - (minus) operators
  • Binary * (multiplication), / (division), % (remainder), + (addition), and - (subtraction) operators

Increment Operator++

The "add one" operator (or ++) means += 1, in other words, it's a quick way to add one integer to a numeric value, without having to type extra code. This operator can be added either before the value or after the value, which would result in a different behavior:

//The result of x++ is the value of x before the operation, as the following example shows:
int i = 4;
Debug.Log(i);   // output: 4
Debug.Log(i++); // output: 4
Debug.Log(i);   // output: 5

//The result of ++x is the value of x after the operation, as the following example shows:
double a = 2.5;
Debug.Log(a);   // output: 2.5
Debug.Log(++a); // output: 3.5
Debug.Log(a);   // output: 3.5

Decrement Operator --

The "subtract one" operator is the opposite of ++ (-= 1), meaning it subtracts one integer from a numeric value. It can also be added before or after a value:

The result of x-- is the value of x before the operation, as the following example shows:
int i = 4;
Debug.Log(i);   // output: 4
Debug.Log(i--); // output: 4
Debug.Log(i);   // output: 3

The result of --x is the value of x after the operation, as the following example shows:
double a = 2.5;
Debug.Log(a);   // output: 2.5
Debug.Log(--a); // output: 1.5
Debug.Log(a);   // output: 1.5

Unary + and - operators

The unary + operator returns the value of its operand and the unary - operator computes the numeric negation of its operand.

Debug.Log(+5);     // output: 5

Debug.Log(-5);     // output: -5
Debug.Log(-(-5));  // output: 5

uint a = 6;
var b = -a;
Debug.Log(b);            // output: -6
Debug.Log(b.GetType());  // output: System.Int64

Debug.Log(-double.NaN);  // output: NaN

Multiplication operator *

The multiplication operator * computes the multiplied product of its operands:

Debug.Log(6 * 3);         // output: 18
Debug.Log(1.5 * 3.5);     // output: 5.25
Debug.Log(0.1m * 24.4m);  // output: 2.44

Division operator /

The division operator / divides its left-hand operand by its right-hand operand.

If one of the operands is decimal, another operand can be neither float nor double, because neither float nor double is implicitly convertible to decimal. You must explicitly convert the float or double operand to the decimal type.

Debug.Log(13 / 5);    // output: 2
Debug.Log(13 / 5.0);       // output: 2.6

int a = 13;
int b = 5;
Debug.Log((double)a / b);  // output: 2.6

Debug.Log(16.8f / 4.1f);   // output: 4.097561
Debug.Log(16.8d / 4.1d);   // output: 4.09756097560976
Debug.Log(16.8m / 4.1m);   // output: 4.0975609756097560975609756098

Remainder operator %

The remainder operator % computes the remainder after dividing its left-hand operand by its right-hand operand.

  • For the operands of integer types, the result of a % b is the value produced by a - (a / b) * b
Debug.Log(5 % 4);   // output: 1
Debug.Log(5 % -4);  // output: 1
Debug.Log(-5 % 4);  // output: -1
Debug.Log(-5 % -4); // output: -1
  • For the decimal operands, the remainder operator % is equivalent to the remainder operator of the System.Decimal type.
Debug.Log(-5.2f % 2.0f); // output: -1.2
Debug.Log(5.9 % 3.1);    // output: 2.8
Debug.Log(5.9m % 3.1m);  // output: 2.8

Addition operator +

The addition operator + computes the sum of its operands. You can also use the + operator for string concatenation and delegate combination.

Debug.Log(6 + 5);       // output: 11
Debug.Log(6 + 5.3);     // output: 11.3
Debug.Log(6.1m + 5.2m); // output: 11.3

Subtraction operator -

The subtraction operator - subtracts its right-hand operand from its left-hand operand. You can also use the - operator for delegate removal.

Debug.Log(48 - 4);      // output: 44
Debug.Log(6 - 5.3);     // output: 0.7
Debug.Log(8.5m - 3.3m); // output: 5.2

2. Comparison operators

The < (less than), > (greater than), <= (less than or equal), and >= (greater than or equal) comparison, also known as relational, operators compare their operands. Those operators are supported by all integral and floating-point numeric types.

Less than operator <

The < operator returns true if its left-hand operand is less than its right-hand operand, false otherwise.

Debug.Log(8.0 < 6.1);   // output: False
Debug.Log(6.1 < 6.1);   // output: False
Debug.Log(1.0 < 6.1);   // output: True

Debug.Log(double.NaN < 6.1);   // output: False
Debug.Log(double.NaN >= 6.1);  // output: False

Greater than operator >

The > operator returns true if its left-hand operand is greater than its right-hand operand, false otherwise.

Debug.Log(8.0 > 6.1);   // output: True
Debug.Log(6.1 > 6.1);   // output: False
Debug.Log(1.0 > 6.1);   // output: False

Debug.Log(double.NaN > 6.1);   // output: False
Debug.Log(double.NaN <= 6.1);  // output: False

Less than or equal operator <=

The <= operator returns true if its left-hand operand is less than or equal to its right-hand operand, false otherwise.

Debug.Log(8.0 <= 6.1);   // output: False
Debug.Log(6.1 <= 6.1);   // output: True
Debug.Log(1.0 <= 6.1);   // output: True

Debug.Log(double.NaN > 6.1);   // output: False
Debug.Log(double.NaN <= 6.1);  // output: False

Greater than or equal operator >=

The >= operator returns true if its left-hand operand is greater than or equal to its right-hand operand, false otherwise.

Debug.Log(8.0 >= 6.1);   // output: True
Debug.Log(6.1 >= 6.1);   // output: True
Debug.Log(1.0 >= 6.1);   // output: False

Debug.Log(double.NaN < 6.1);   // output: False
Debug.Log(double.NaN >= 6.1);  // output: False

3. Boolean logical operators

The following operators perform logical operations with bool operands:

  • Unary ! (logical negation) operator.
  • Binary & (logical AND), | (logical OR), and ^ (logical exclusive OR) operators. Those operators always evaluate both operands.
  • Binary && (conditional logical AND) and || (conditional logical OR) operators. Those operators evaluate the right-hand operand only if it's necessary.

Logical negation operator !

The unary prefix ! operator computes the logical negation of its operand. That is, it produces true, if the operand evaluates to false, and false, if the operand evaluates to true.

bool passed = false;
Debug.Log(!passed);  // output: True
Debug.Log(!true);    // output: False

Logical AND operator &

The & operator computes the logical AND of its operands. The result of x & y is true if both x and y evaluate to true. Otherwise, the result is false.

The & operator evaluates both operands even if the left-hand operand evaluates to false, so that the operation result is false regardless of the value of the right-hand operand.

bool SecondOperand()
{
    Debug.Log("Second operand is evaluated.");
    return true;
}

bool a = false & SecondOperand();
Debug.Log(a);
// Output:
// Second operand is evaluated.
// False

bool b = true & SecondOperand();
Debug.Log(b);
// Output:
// Second operand is evaluated.
// True

Logical exclusive OR operator ^

The ^ operator computes the logical exclusive OR, also known as the logical XOR, of its operands. The result of x ^ y is true if x evaluates to true and y evaluates to false, or x evaluates to false and y evaluates to true. Otherwise, the result is false. That is, for the bool operands, the ^ operator computes the same result as the inequality operator !=.

Debug.Log(true ^ true);    // output: False
Debug.Log(true ^ false);   // output: True
Debug.Log(false ^ true);   // output: True
Debug.Log(false ^ false);  // output: False

Logical OR operator |

The | operator computes the logical OR of its operands. The result of x | y is true if either x or y evaluates to true, otherwise, the result is false.

The | operator evaluates both operands even if the left-hand operand evaluates to true, so that the operation result is true regardless of the value of the right-hand operand.

bool SecondOperand()
{
    Debug.Log("Second operand is evaluated.");
    return true;
}

bool a = true | SecondOperand();
Debug.Log(a);
// Output:
// Second operand is evaluated.
// True

bool b = false | SecondOperand();
Debug.Log(b);
// Output:
// Second operand is evaluated.
// True

Conditional logical AND operator &&

The conditional logical AND operator &&, also known as the "short-circuiting" logical AND operator, computes the logical AND of its operands. The result of x && y is true if both x and y evaluate to true, otherwise, the result is false. If x evaluates to false, y is not evaluated.

bool SecondOperand()
{
    Debug.Log("Second operand is evaluated.");
    return true;
}

bool a = false && SecondOperand();
Debug.Log(a);
// Output:
// False

bool b = true && SecondOperand();
Debug.Log(b);
// Output:
// Second operand is evaluated.
// True

Conditional logical OR operator ||

The conditional logical OR operator ||, also known as the "short-circuiting" logical OR operator, computes the logical OR of its operands. The result of x || y is true if either x or y evaluates to true. Otherwise, the result is false. If x evaluates to true, y is not evaluated.

bool SecondOperand()
{
    Debug.Log("Second operand is evaluated.");
    return true;
}

bool a = true || SecondOperand();
Debug.Log(a);
// Output:
// True

bool b = false || SecondOperand();
Debug.Log(b);
// Output:
// Second operand is evaluated.
// True

4. Bitwise and shift operators

The following operators perform bitwise or shift operations with operands of the integral numeric types or the char type:

  • Unary ~ (bitwise complement) operator
  • Binary << (left shift) and >> (right shift) shift operators
  • Binary & (logical AND), | (logical OR), and ^ (logical exclusive OR) operators

Bitwise complement operator ~

The ~ operator produces a bitwise complement of its operand by reversing each bit.

uint a = 0b_0000_1111_0000_1111_0000_1111_0000_1100;
uint b = ~a;
Debug.Log(Convert.ToString(b, toBase: 2));
// Output:
// 11110000111100001111000011110011

Left-shift operator <<

The << operator shifts its left-hand operand left by the number of bits defined by its right-hand operand. For information about how the right-hand operand defines the shift count, see the Shift count of the shift operators section.

uint x = 0b_1100_1001_0000_0000_0000_0000_0001_0001;
Debug.Log($"Before: {Convert.ToString(x, toBase: 2)}");

uint y = x << 4;
Debug.Log($"After:  {Convert.ToString(y, toBase: 2)}");
// Output:
// Before: 11001001000000000000000000010001
// After:  10010000000000000000000100010000

Right-shift operator >>

The >> operator shifts its left-hand operand right by the number of bits defined by its right-hand operand.

uint x = 0b_1001;
Debug.Log($"Before: {Convert.ToString(x, toBase: 2), 4}");

uint y = x >> 2;
Debug.Log($"After:  {Convert.ToString(y, toBase: 2), 4}");
// Output:
// Before: 1001
// After:    10

The high-order empty bit positions are set based on the type of the left-hand operand as follows:

  • If the left-hand operand is of type int or long, the right-shift operator performs an arithmetic shift: the value of the most significant bit (the sign bit) of the left-hand operand is propagated to the high-order empty bit positions. That is, the high-order empty bit positions are set to zero if the left-hand operand is non-negative and set to one if it's negative.
int a = int.MinValue;
Debug.Log($"Before: {Convert.ToString(a, toBase: 2)}");

int b = a >> 3;
Debug.Log($"After:  {Convert.ToString(b, toBase: 2)}");
// Output:
// Before: 10000000000000000000000000000000
// After:  11110000000000000000000000000000
  • If the left-hand operand is of type uint or ulong, the right-shift operator performs a logical shift: the high-order empty bit positions are always set to zero.
uint c = 0b_1000_0000_0000_0000_0000_0000_0000_0000;
Debug.Log($"Before: {Convert.ToString(c, toBase: 2), 32}");

uint d = c >> 3;
Debug.Log($"After:  {Convert.ToString(d, toBase: 2), 32}");
// Output:
// Before: 10000000000000000000000000000000
// After:     10000000000000000000000000000

Logical AND operator &

The & operator computes the bitwise logical AND of its integral operands.

uint a = 0b_1111_1000;
uint b = 0b_1001_1101;
uint c = a & b;
Debug.Log(Convert.ToString(c, toBase: 2));
// Output:
// 10011000

Logical exclusive OR operator ^

The ^ operator computes the bitwise logical exclusive OR, also known as the bitwise logical XOR, of its integral operands.

uint a = 0b_1111_1000;
uint b = 0b_0001_1100;
uint c = a ^ b;
Debug.Log(Convert.ToString(c, toBase: 2));
// Output:
// 11100100

Logical OR operator |

The | operator computes the bitwise logical OR of its integral operands.

uint a = 0b_1010_0000;
uint b = 0b_1001_0001;
uint c = a | b;
Debug.Log(Convert.ToString(c, toBase: 2));
// Output:
// 10110001

5. Equality operators

The == (equality) and != (inequality) operators check if their operands are equal or not.

Equality operator ==

The equality operator == returns true if its operands are equal, false otherwise.

int a = 1 + 2 + 3;
int b = 6;
Debug.Log(a == b);  // output: True

char c1 = 'a';
char c2 = 'A';
Debug.Log(c1 == c2);  // output: False
Debug.Log(c1 == char.ToLower(c2));  // output: True

Inequality operator !=

The inequality operator != returns true if its operands are not equal, false otherwise. For the operands of the built-in types, the expression x != y produces the same result as the expression !(x == y).

int a = 1 + 1 + 2 + 3;
int b = 6;
Debug.Log(a != b);  // output: True

string s1 = "Hello";
string s2 = "Hello";
Debug.Log(s1 != s2);  // output: False

object o1 = 2;
object o2 = 2;
Debug.Log(o1 != o2);  // output: True

6. Miscellaneous operators

Common miscellaneous operators are ?: for conditional checks, :: for accessing a member of an aliased namespace, and $ for string interpolation.

?: operator

The conditional operator ?:, also known as the ternary conditional operator, evaluates a Boolean expression and returns the result of one of the two expressions, depending on whether the Boolean expression evaluates to true or false, as the following example shows:

bool condition = true;
Debug.Log(condition ? 1 : 2); // output: 1

:: operator

Use the namespace alias qualifier :: to access a member of an aliased namespace. You can use the :: qualifier only between two identifiers. The left-hand identifier can be any of the following aliases:

  • A namespace alias created with a using alias directive:
using forwinforms = System.Drawing;
using forwpf = System.Windows;

public class Converters
{
    public static forwpf::Point Convert(forwinforms::Point point) => new forwpf::Point(point.X, point.Y);
}
  • An extern alias.
  • The global alias, which is the global namespace alias. The global namespace is the namespace that contains namespaces and types that are not declared inside a named namespace. When used with the :: qualifier, the global alias always references the global namespace, even if there is the user-defined global namespace alias.
namespace MyCompany.MyProduct.System
{
    class Program
    {
        static void Main() => global::System.Console.WriteLine("Using global alias");
    }

    class Console
    {
        string Suggestion => "Consider renaming this class";
    }
}

$ operator

The $ special character identifies a string literal as an interpolated string. An interpolated string is a string literal that might contain interpolation expressions. When an interpolated string is resolved to a result string, items with interpolation expressions are replaced by the string representations of the expression results.

In Interpolated Strings, the dollar sign ($) is used to tell the C# compiler that the string following it is to be interpreted as an Interpolated String. The curly braces encapsulate the values (of the variables) to include in the text.

To identify a string literal as an interpolated string, prepend it with the $ symbol. You can't have any white space between the $ and the " that starts a string literal.

string name = "John";
var date = DateTime.Now;
Debug.Log($"Hello, {name}! Today is {date.DayOfWeek}, it's {date:HH:mm} now.");
// Output:
// Hello, John! Today is Wednesday, it's 19:40 now.
Links
Unity