HowTo – C# Operators

Source Code

All source code can be found on GitHub here.

This is part of my HowTo in .NET seriies. An overview can be seen here,

 

Operators


An operator applies to either one operand (unary), between two operands (binary) or three operators (ternary).

The operands are referenced by their ordinal position from left to right.

The following addition operator is a binary operator and has two operands, the first being 1 and the second being 2.

int x = 1 + 2;

The following sections define the available C# operators, their meanings and provide an example of their usage.

The precedence of the operators (their order of evaluation where multiple operators exist) is traversed from the highest priority to the least priority as we go through this chapter.

A Note On Binary Bits

Binary bits are a sequence of 1’s and 0’s. They are mapped to values 1, 2, 4, 8, 16, 32, 64 etc (doubling) going from the least significant bit to the most significant.

The order of bits depends upon the endianness of the system; bigendian runs largest mapped value to smallest while littleendian runs smallest mapped value to largest.

The examples laid out for bitwise operations are laid out as if bigendian and to save confusion their mapping values are provided as a heading:

16

8

4

2

10

1

0

1

1

=

11

A Note On Hexadecimal Values

A hexadecimal or hex is a sequence of any number of 16 characters, each of which map to an integral value.

Normally the numbers 0-9 and the letters A,B,C,D,E and F are used to represents the values 0 to 15.

The main use of hexadecimal representations are to provide a more human friendly representation of binary code.

Each hexadecimal digit represents four binary bits or a byte.

A byte has a range of 0-255 and in hex it can be represented as a range of 00 to FF.

To convert from a decimal to a hex involves continuous division and modulus of 16. The modulus is used to populate the current hex digit, the result of the division rounded down to the nearest integer is used as the input to the next calculation (Divide By 16 (Whole)).

The following shows that 255 as hexadecimal is FF:

Input

Divide By 16 (whole)

Moduls

Hex of Modulus

Ordinal Position

255

15

15

F

0

15

0

15

F

1

The following shows that 48129 in hexadecimal is BC01:

Input

Divide By 16 (whole)

Moduls

Hex of Modulus

Ordinal Position

48129

3008

1

1

0

3008

188

0

0

1

188

11

12

C

2

11

0

11

B

3

To convert hex back into decimal, take each hex as a 0-15 representation and multiply it by 16 to the power of its ordinal position; then and add them all up.

The following shows that FF in decimal is 255:

F

F

Decimal Result

15*(16^1)

15*(16^0)

240 +

15

= 255

The following shows that BC01 in decimal is 48129:

B

C

0

1

Decimal Result

11*(16^3)

12*(16^2)

0*(16^1)

1*(16^0)

45056 +

3072 +

0 +

1

= 48129

Hex in C# are declared as integer types and prefixed with 0x:

int ff = 0xFF;

Primary Operators

Name

Operator

Definition

Example

Member Access

x.y

Member access

var data = MyClass.MyData;

Parentheses

f(x)

Method invocation

Override operator precedence

MyClass.Do();

var foo = (1 * 2 ) / 4;

Square brackets /

Indexer

a[x]

Array declaration

Collection index methods

Attribute declarations

var myArray = new string[6]; // declare

myArray[0] = “Hello”; // Indexer

[Serializable] public class { } // attribute

Postfix increment

x++;

Assignment followed by increment

var x = y++;  // y will be +1 of x

Postfix decrement

x–;

Assignment made before decrement

var x = y–;   // y will be -1 of  x

new

new

Create objects and invoke constructors

var foo = new Foo();

typeof

typeof

Returns the Type descriptor of a defined type

System.Type type = typeof(int);

checked

checked

Enforces overflow-checking when an application has been set to not enforce them

checked { }

unchecked

unchecked

Suppresses overflow-checking in an application which has been set to enforce them

unchecked { }

default(T)

default(T)

Allow calling the default constructor for a value type

var aDefault = default(T);

var zero = default(T);

delegate

delegate

Defines a delegate type

delegate int MyDel(string foo);

sizeof

sizeof

Returns the size in bytes for a type

var size = sizeof(int);

->

->

Pointer dereferencing and member access. It can only be used in unsafe code

x ->y = 1;

// In safe code this would read x.y = 1

// By passing the type safety

// The same as (*x).y

Unary Operators

Name

Operator

Definition

Example

Unary plus

+x

Defines a positive numeric data type

var foo = +1; // same as foo = 1

Unary minus

-x

Negates a numeric data type

var foo = -1; // same as foo = -1

Logical negation

!x

Negates the operand

var foo = !true; // foo = false;

Deconstructor

~x

Declares a deconstructor method.

It is called before the garbage collector removes the reference type from the heap but before the object is fully removed from memory

public class foo

{

   ~foo() { }

}

Prefix increment

++x

Increment the operand and then assign the result

var x = ++y;  // y will be x

Prefix decrement

–x

Decrement the operand and then assign the result

var x = –y;   // y will be x

Explicit cast

(T)x

Explicitly cast one type to another. Any data type narrowing can cause data to be lost.

var myInt = (int)16.4m;

await

await

Suspends thread execution until an asynchronous method call has finished

var aTask = foo.DoAsync(url);

var data = await aTask;

Unary and

Binary &

&x

Unary & returns the address of its operand. It can only be used in an unsafe context

Binary & performs a bitwise AND operation between two data types.

var oo & 22;

var foo = 0xB & 0x16  // 11 & 22  = 2

16

8

4

2

10

1

0

1

1

=

11

&

1

0

1

1

0

=

22

0

0

0

1

0

=

2

*x operator

*x

Declares a pointer reference; can only be used in unsafe regions

int* x = y

Multiplicative Operators

Name

Operator

Definition

Example

Multiplication

x * y

Multiples two operands

var foo = 2 * 2; // foo = 4

Division

x / y

Divides two operands

var foo = 4 / 2; // foo = 2

Modulus

x % y

Returns the difference between two operands and the division operator

var foo = 5 % 2; // foo = 1

Additive Operators

Name

Operator

Definition

Example

+ operator

x + y

Adds two numerical data types

var foo = 2 + 2; // foo = 4

– operator

x – y

Difference between two numerical data types

var foo = 4 – 2; // foo = 2

Shift Operators

Name

Operator

Definition

Example

Left-Shift

x << y

Shifts the first operand to the left by the integral number of places defined by the second operand.

Any high ends bits which are not within range of the type are discarded.

The new low end bits are filled with 0’s

var foo = 0x7 << 1;

//  1110 = 111 << 1

8

4

2

1

1

1

1

=

7

<< 1

1

1

1

0

=

14

Right Shift

x >> y

Shifts the first operand to the right by the integral number defined by the second operand

Any low ends bits which are not within range of the type are discarded.

The new high end bits are filled with 0’s

var foo = 0x14 >> 1

// 0111 = 1110 >> 1

8

4

2

1

1

1

1

0

=

14

>> 1

0

1

1

0

=

7

Relational and Type Testing Operators

Name

Operator

Definition

Example

Less Than

x < y

Returns true if the first operand is less than the second

var foo = 1 < 2; // foo = true

Greater Than

x > y

Returns true if  the first operand is greater than the second

var foo = 1 > 0; // foo = true

Less Than

Or Equal

x <= y

Returns true if  the first operand is less than or equal to the second

var foo = 2 <= 2; // foo = true

Greater Than

Or Equal

x >= y

Returns true if the first operand is greater than or equal to the second

var foo = 0 >= 0; // foo = true

Is

is

Returns true if the first operand can be safely cast to the other:.

The cast is safe if  the second operand is an implemented interface,  an ancestor or an explicit/implicit cast method has been provided.

var foo = aChild  is Parent ;

var foo = aChild is IChild;

As

as

Returns the first operand cast into the type if  the cast can safely be performed, otherwise null is returned

The cast is safe if  the second operand is an implemented interface,  an ancestor or an explicit/implicit cast method has been provided.

var foo = aChild as Parent;

if( foo != null) { }

Equality Operators

Name

Operator

Definition

Example

Equality

x == y

Performs an equality test between two operands.

For value types and strings this is based on equality.

For reference types this is upon identity unless the Equals method has been overridden.

var foo = aChild == aChild;;

Not Equal

x != y

Performs an inequality test between two operands.

For value types and strings this is based on equality.

For reference types this is upon identity unless the Equals method has been overridden.

var foo = aChild == bChild;

Logical & Conditional Operators

Name

Operator

Definition

Example

Logical AND

Bitwise AND

x & y

Logical AND returns true if two operands evaluate to true. The second operand is evaluated regardless of the result of the first operand.

Bitwise AND performs an AND operation between aligned bits of two types. Bits at the same ordinal position are compared.

var foo = isX() & isY();

var foo = 0x11 & 0x16

// 2 = 11 & 22;

16

8

4

2

1

1

0

1

1

=

11

1

0

1

1

0

=

22

0

0

0

1

0

=

2

Logical XOR

x ^y

Performs bitwise exclusive OR operations between two operands which can be booleans or binary.

For boolean; returns true if only one of the operands is true. For all other combinations returns false,

For binary data each bit is compared to the same bit at the same ordinal position and an exclusive OR is performed.

var foo = true ^ true; // false

var foo = false^ true; // true

var foo = false ^ false; // false

var foo = 0x11 ^ 0x16;

//var foo = 11 ^ 22;

16

8

4

2

1

1

0

1

1

=

11

1

0

1

1

0

=

22

1

1

1

0

1

=

29

Logical OR

Bitwise OR

x | y

Returns true if either the first or second operand evaluates to true

The second operand is evaluated regardless of the result of the first operand

For binary data each bit is compared to the same bit in the same ordinal position and an OR is performed.

var foo = isX() | isY();

var foo = 0x11 ^ 0x16;

//var foo = 11 ^ 22;

16

8

4

2

1

1

0

1

1

=

11

1

0

1

1

0

=

22

1

1

1

1

1

=

31

Conditional AND

x && y

Returns true if the first and second operand evaluates to true

The second operand is only evaluated if the first operand evaluates to true

var foo = isX() && isY();

Conditional OR

x || y

Returns true if the first or second operand evaluates to true

The second operand is only evaluated if the first operand evaluates to false

var foo = isX() || isY();

Null

Coalescing

x ?? y

Allows defining a value if the first operand is null

int? x;

int y = x ?? -1;  // y = -1 as x is null

Conditional

?

If the first operand evaluates to true the second operand is returned otherwise the third operand is returned,

condition ? trueOperand: falseOperand;;

var foo = isTrue() ? “Yay!”: “Ohh noo!”;

// if isTrue() foo = “Yay! “ otherwise foo = “Ohh noo!”

Assignment and Lambda Expression Operators

Name

Operator

Definition

Example

Assignment

x = y

Assigns one type to the other

Value types are copied, reference types have their reference copied and will therefore remain pointing to the same underlying object.

Structs containing reference and value types will have value type members copied and reference types will have their references  copied; they will remain pointing to the same object

var foo = moo;

// foo is now moo

Addition Assignment

x += y

Adds the second operand onto the first and assigns the result to the first operand.

x += 1; // same as x = x + 1;

Subtraction Assignment

x -= y

Subtracts the second operator from the first and assigns the result to the first operand.

x -= 1; // same as x = x – 1;

Binary Multiplication Assignment

x *= y

The first and second operator are multiplied together and the result is assigned to the first.

x *= 2;  // same as x = x * 2;

Division Assignment

x /= y

The first operator is divided by the second operator and the result is assigned to the first

x /= 2;  // same as x = x / 2;

Remainder Assignment

x %= y

The divisional remainder between the first and second operator is assigned to the first

x %= 2; // same as x = x % 2;

AND Assignment

x &= y

The the Logical AND operator is applied between the two operands and the result is assigned to the first operand

x &= y; // same as x = x & y;

OR Assignment

x |= y

The Logical OR operator is applied between two operands and the result is applied to the first operand

x |= y; // same as x = x | y;

Exclusive OR Assignment

x ^= y

The Exclusive OR operator is applied between two operands and the result is applied to the first operand

x ^= y; // same as x = x ^ y;

Left-Shift

x <<= y

The left-shift operator is applied between two operands and the result is applied to the first operand.

x <<= y; // same as x = x << y

Right-Shift

x >>= y

The right-shift operator is applied between two operands and the result is assigned to the first operand.

x >>= y; // same as x = x >> y

Lambda

=>

Defines a lambda anonymous function declaration

aList.First( x => x.IsFoo());