Data Types

Every value in C# has a type that decides what it can hold, how much memory it uses and what you can do with it. This lesson tours the built-in types — integers, floating-point and decimal numbers, booleans, characters and strings — and introduces the important split between value types and reference types.

The built-in types

Keyword.NET typeHoldsSize
intInt32Whole numbers, about ±2.1 billion4 bytes
longInt64Whole numbers, about ±9.2 quintillion8 bytes
short / byteInt16 / ByteSmall whole numbers (byte: 0–255)2 / 1 bytes
doubleDoubleFloating-point numbers, ~15–17 significant digits8 bytes
floatSingleFloating-point, ~6–9 digits4 bytes
decimalDecimalExact base-10 numbers with 28–29 digits — for money16 bytes
boolBooleantrue or false1 byte
charCharOne UTF-16 character, such as 'A'2 bytes
stringStringText of any lengthvaries

There are also unsigned versions (uint, ulong, ushort) and sbyte, but you'll rarely need them. For everyday code: int for counts, double for measurements, decimal for money, bool, char and string.

Ranges and sizes

Each numeric type exposes its limits as MinValue and MaxValue, and sizeof gives its size in bytes:

C#
Console.WriteLine($"int:  {int.MinValue} to {int.MaxValue}");
Console.WriteLine($"long: {long.MinValue} to {long.MaxValue}");
Console.WriteLine($"byte: {byte.MinValue} to {byte.MaxValue}");
Console.WriteLine($"sizes: int {sizeof(int)}, long {sizeof(long)}, double {sizeof(double)}, decimal {sizeof(decimal)}, char {sizeof(char)}");
Output
int:  -2147483648 to 2147483647
long: -9223372036854775808 to 9223372036854775807
byte: 0 to 255
sizes: int 4, long 8, double 8, decimal 16, char 2

Number literals

A whole number like 42 is an int, and a number with a decimal point like 4.2 is a double. A suffix picks another type. Underscores make long numbers readable, and 0x / 0b write hexadecimal and binary:

C#
long distance = 9_460_730_472_580_800L;  // L = long
float ratio = 0.5f;                       // f = float
decimal price = 19.99m;                   // m = decimal
int mask = 0b1010_1010;                   // binary
int colour = 0xFF8800;                    // hexadecimal
double avogadro = 6.022e23;               // scientific notation

Console.WriteLine(distance);
Console.WriteLine(ratio);
Console.WriteLine(price);
Console.WriteLine(mask);
Console.WriteLine(colour);
Console.WriteLine(avogadro);
Output
9460730472580800
0.5
19.99
170
16746496
6.022E+23

Forgetting the m on a decimal is a common mistake — the compiler won't silently turn a double into a decimal:

C#
decimal price = 19.99;
Build error
Program.cs(1,17): error CS0664: Literal of type double cannot be implicitly converted to type 'decimal'; use an 'M' suffix to create a literal of this type

Booleans

A bool holds true or false, usually the result of a comparison. Unlike C, numbers are not booleans: you can't write if (1).

C#
int age = 20;
bool isAdult = age >= 18;
bool hasTicket = false;

Console.WriteLine(isAdult);
Console.WriteLine(isAdult && hasTicket);
Output
True
False

Characters

A char is one character in single quotes. Under the hood it's a 16-bit number (a UTF-16 code unit), so you can convert it to and from int:

C#
char grade = 'B';
char next = (char)(grade + 1);

Console.WriteLine(grade);
Console.WriteLine((int)grade);
Console.WriteLine(next);
Console.WriteLine(char.IsLetter(grade));
Console.WriteLine(char.IsDigit('7'));
Output
B
66
C
True
True

Default values

Every type has a default value: zero for numbers, false for bool, the zero character for char, and null (no object) for reference types like string. Fields of a class start out with these defaults, and you can ask for one with default:

C#
Console.WriteLine(default(int));
Console.WriteLine(default(bool));
Console.WriteLine(default(decimal));
Console.WriteLine(default(char) == '\0');
Output
0
False
0
True

Value types and reference types

C# types come in two families, and the difference affects how assignment works:

  • Value types — all the numeric types, bool, char, and structs (lesson 40). The variable holds the value itself. Assigning copies the value.
  • Reference types — string, arrays, classes and lists. The variable holds a reference to an object stored elsewhere (on the heap). Assigning copies the reference, so both variables point at the same object.
C#
int a = 10;
int b = a;      // copies the value
b = 99;
Console.WriteLine($"a = {a}, b = {b}");

int[] first = [1, 2, 3];
int[] second = first;   // copies the reference
second[0] = 99;
Console.WriteLine($"first[0] = {first[0]}");
Output
a = 10, b = 99
first[0] = 99

Changing b didn't affect a, but changing the array through second also changed first — they're the same array. Strings are reference types too, but they can never be modified (lesson 16), so they behave like values in practice.

Everything is an object

All types derive from object, so every value has methods such as ToString() and GetType():

C#
Console.WriteLine(42.ToString() + "!");
Console.WriteLine(3.5.GetType());
Console.WriteLine("hi".GetType());
Console.WriteLine(typeof(bool));
Output
42!
System.Double
System.String
System.Boolean

Try it yourself

Print the largest long, then add 1 to int.MaxValue stored in a long variable. Lesson 8 shows what happens if you do it with an int.

Try it yourself · Program.cs
Edit the code, copy it into Program.cs and run it with dotnet run Program.cs (.NET 10 or later). How to set up .NET
Output
9223372036854775807
2147483648
short holds -32768 to 32767