.NET Documentation

Types in .NET Core

Understanding types is fundamental to programming in .NET Core. Types define the structure and behavior of data. .NET Core employs a rich type system that allows for flexibility and powerful abstractions.

Value Types vs. Reference Types

A core distinction in the .NET type system is between value types and reference types.

Value Types

Value types directly contain their data. When you assign a value type to another variable, a copy of the value is made.

Common examples include:

  • Primitive types: int, float, bool, char
  • Structures (struct): User-defined types that behave like primitive types.
  • Enums (enum): Define a set of named constants.
int a = 10;
int b = a; // b is a copy of a
b = 20;   // a remains 10

Reference Types

Reference types store a reference (or pointer) to the memory location where the object's data resides. When you assign a reference type to another variable, both variables point to the same object in memory.

Common examples include:

  • Classes (class): The most common reference type.
  • Arrays: A collection of elements of the same type.
  • Delegates: Type-safe function pointers.
  • Interfaces: Contracts that define a set of members.
  • Strings (string): Although immutable, they are reference types.
List<int> list1 = new List<int>() { 1, 2 };
List<int> list2 = list1; // list2 points to the same list as list1
list2.Add(3);          // list1 now also contains 3

Common Type System (CTS)

The Common Type System (CTS) is a set of types and operations that can be used by all languages targeting the .NET Common Language Runtime (CLR). This ensures interoperability between code written in different .NET languages.

Type Inference

.NET Core supports type inference, where the compiler can deduce the type of a variable based on the value assigned to it. This is often used with the var keyword.

var message = "Hello, .NET!"; // Compiler infers message is a string
var count = 100;              // Compiler infers count is an int

Generics

Generics allow you to define types and methods that operate on a specified type parameter. This provides compile-time type safety and improves code reusability.

// Generic List
List<string> names = new List<string>();
names.Add("Alice");

// Generic method
public static T FindMax<T>(T a, T b) where T : IComparable<T>
{
    return a.CompareTo(b) > 0 ? a : b;
}

Nullability

In .NET Core, reference types are nullable by default, meaning they can hold a null value. Value types, on the other hand, cannot be null. However, with nullable reference types, you can explicitly indicate whether a reference type is intended to be nullable, helping to prevent NullReferenceException at compile time.

string? nullableName = null; // Explicitly nullable
string nonNullableName = "Bob"; // Cannot be null (with nullable reference types enabled)