C# Data Types

Every variable has a type. Types in C# are split into value types and reference types. This split decides where data lives, how copies behave, and whether null is allowed.

Type System

Value Types

Value types store data directly and use copy semantics. They cannot be null (except nullable wrappers).

  • Integers: byte, short, int, long
  • Floating point: float, double, decimal
  • Other: bool, char, enum, struct

Reference Types

Reference types store a reference to data on the heap and use reference semantics. They default to null.

  • Classes, interfaces, delegates
  • string and arrays
  • Records declared with record class

Value vs Reference

AspectValue typeReference type
StorageInlineHeap
CopyCopies dataCopies reference
DefaultZero valuenull
EqualityBy valueBy reference (unless overridden)

Watch how copies behave: value types copy the data, reference types copy the reference — both names end up seeing the same array.

int a = 5;
int b = a;          // b gets a COPY of 5 (value type)
b = 10;             // a is unchanged: still 5

int[] x = { 1, 2 };
int[] y = x;        // y gets a REFERENCE to the same array
y[0] = 99;          // x[0] is now 99 too — both names see one object

Declarations

Explicit Typing

Start with explicit types: the declaration documents itself and beginners see exactly which type is used.

int age = 30;
double price = 19.99;
bool enabled = true;
string name = "Ada";

var Keyword

var asks the compiler to infer the type. The type is fixed at compile time; this is not dynamic typing.

var count = 7;          // int
var label = "total";    // string
var values = new List<int>(); // List<int>

Nullable Types

Suffix ? lets a value type hold null. Test with HasValue and read with Value.

int? score = null;
score = 42;
if (score.HasValue)
{
    Console.WriteLine(score.Value);
}

Literals

Literals write a value into code: 42, 42L (long), 19.99m (decimal), 'A' (char), "text" (string), true.

Common Pitfalls

Integer Overflow

Arithmetic that exceeds a type range wraps silently in an unchecked context. Wrap code in checked to force an exception.

int big = int.MaxValue;
// int overflow = big + 1; // wraps to negative in unchecked context
int overflow = checked(big + 1); // throws OverflowException

Floating Point Precision

double is binary and cannot represent all decimals exactly. Use decimal for money and exact arithmetic.

double d = 0.1 + 0.2;      // 0.30000000000000004
decimal m = 0.1m + 0.2m;    // 0.3 exactly