C# Type System

Introduction to Types

The C# type system is a fundamental aspect of the language, defining how data is stored, manipulated, and interpreted. Every value in C# has a specific type, which dictates its behavior and the operations that can be performed on it.

C# supports a rich set of built-in types, also known as primitive types, as well as user-defined types that can be created using classes, structs, enums, and delegates. The Common Type System (CTS), part of the Common Language Infrastructure (CLI), provides a common framework for type definitions across different .NET languages.

Value Types vs. Reference Types

In C#, types are broadly categorized into two main groups: value types and reference types.

Value Types

Value types directly contain their data. When you assign a value type variable to another, the value is copied. Common examples include primitive types like int, float, bool, and structs.

Value Type Example


int a = 10;
int b = a; // b gets a copy of the value 10
b = 20;    // Changes b, but a remains 10
                    

In this example, both a and b are independent variables, each holding its own copy of an integer value.

Reference Types

Reference types store a reference (an address) to the actual data, which is located on the managed heap. When you assign a reference type variable to another, both variables point to the same object in memory. Examples include classes, interfaces, delegates, and strings (though strings are immutable).

Reference Type Example


List<int> list1 = new List<int>();
list1.Add(10);
List<int> list2 = list1; // list2 refers to the same object as list1
list2.Add(20);
// Now list1 also contains 10 and 20
                    

Here, list1 and list2 both point to the same List<int> object. Modifying the list through list2 affects what is visible through list1.

Built-in Types

C# provides a comprehensive set of built-in types, which map to types defined in the .NET Framework. These can be categorized as follows:

Numeric Types

Used for representing numbers.

  • Integers: sbyte, byte, short, ushort, int, uint, long, ulong
  • Floating-Point: float, double
  • Decimal: decimal (for high precision financial calculations)

Boolean Type

Represents a truth value: bool (true or false).

Character Type

Represents a single Unicode character: char.

String Type

Represents a sequence of Unicode characters: string. Strings in C# are immutable.

Reference Types (Built-in)

While class and interface are keywords for user-defined types, types like object (the base type of all types) and string are also fundamental reference types.

Note: C# provides aliases for .NET types. For example, int is an alias for System.Int32, and string is an alias for System.String.

User-Defined Types

Beyond built-in types, developers can create their own types to model complex data and behavior.

Classes

The cornerstone of object-oriented programming in C#. Classes define the blueprint for objects, encapsulating data (fields) and behavior (methods).

Structs

Similar to classes but are value types. They are typically used for small, lightweight data structures.

Enums

Define a set of named constants, making code more readable and maintainable.

Interfaces

Define contracts that classes or structs must implement, specifying a set of members that the implementing type must provide.

Delegates

Represent references to methods with a particular parameter list and return type, enabling event handling and callbacks.

Type Safety

C# is a type-safe language. This means that the compiler enforces strict rules about how types can be used, preventing operations that are not defined for a given type. This helps to catch errors at compile time rather than at runtime, leading to more robust applications.

For example, you cannot directly assign an integer to a string variable without explicit conversion, nor can you call a method on an object that is not declared to have that method.

Nullability

Value types, by default, cannot be null. However, you can declare nullable value types using the ? modifier (e.g., int?, bool?). Reference types can be null, indicating that the variable does not refer to any object.

Nullable Value Type


int? nullableInt = null; // This is valid
if (nullableInt.HasValue)
{
    Console.WriteLine(nullableInt.Value);
}
else
{
    Console.WriteLine("The integer is null.");
}