Conversions & Casting

C# is statically typed at compile time. Once a variable is typed, it cannot hold a different type.

Implicit Conversions (Conversions)

Implicit conversions happen automatically, always succeed, and no data is lost.
Example: converting from a long to an int.

Derived to Base Type

A derived class always contains all members of a base class.

Explicit Conversions (Casting)

Casting is required when data may be lost in the conversion, or if the conversion may otherwise fail:

double x = 1234.7
int a;
a = int(x); // Casting is required because data will be lost.
// a = 1234

Casting between reference types does not change the run-time type of the underlying object.

Base to Derived Type

Explicit conversion is required; will throw an InvalidCastException at run time if the right-side object is not the left-side type:

Giraffe g = new();
Animal a = g; // Implicit conversion: safe.
Giraffe g2 = (Giraffe)a; // If a is not a Giraffe, throw InvalidCastException.

User-defined Conversions

Special methods that enable explicit and implicit conversions between custom types that do not have a base–derived class relationship.

Conversions with Helper Classes

Used to convert between non-compatible types like int and DateTime.

Use the BitConverter class to convert an array of bytes into primitive data types.

Converting Strings to Numbers

Use the Parse() and TryParse() methods of numeric types.

When using Parse(), always catch FormatException for when the parse fails:

string input = "123";
try { 
	int result = Int32.Parse(input);
}
catch (FormatException ex) {  }

TryParse() will return boolean if the parse can succeed and, if true, store it in an out variable:

string input = "123";
if (int.TryParse(input, out int result) {  }

Use methods of the Convert type for general objects that implement IConvertible:

Convert.ToDecimal(input);

Convert to/from Base64 String

// Convert a byte array to a base 64 string:
byte[] bytes = { 1, 2, 4, 8, 16, 32 };
string b64 = Convert.ToBase64String(bytes);

// Convert a base 64 string to a byte array:
byte[] newBytes = Convert.FromBase64String(b64);

Convert to/from UTF-8

using System.Text;

// Convert a UTF-8 JSON string to bytes:
byte[] bytes = Encoding.UTF8.GetBytes(string);

Avoiding Casting Exceptions

Use the is or as keywords as shown here.
Alternatively, write try-catch for InvalidCastException.

Using Pattern Matching

is Statement

Use the is statement to cast without the risk of an InvalidCastException.

if (a is Mammal m) {
	// If a is a Mammal, declare new Mammal m and set m = a.
}

Equivalent to:

if (a is Mammal) {
	Mammal m = (Mammal)a;
}

as Statement

Use the as statement to cast without the risk of an InvalidCastException.

var m = o as Mammal; // If o is a Mammal, set m = o.  Else, m = null.
if (m != null) {  }

Pattern Matching Switch Example

static void PatternMatchingSwitch (System.ValueType val) {
	switch (val) {
		case int number: 
		case long number: 
		case decimal number: 
	}
}