02. Variables and Types
C# is a statically-typed language — every variable has its type fixed at declaration. In this lecture you'll learn value types (int, double, bool, char...), reference types (string, object), conversion, and the var keyword.
What you'll learn
- 1Know the size and range of the basic types `int`/`long`/`double`/`decimal`/`bool`/`char`/`string`
- 2Understand the difference between **value types** and **reference types**
- 3Use `var` / `const` / `readonly` in the right places
- 4Understand string immutability
- 5Know what **boxing** is and why it's slow
Overview
Programming is, at its core, "remembering and transforming values." C# is a **statically-typed** language, so every variable's type is decided at compile time. In this lecture we solidify the basic types and the difference between value and reference types.
Core Concepts
1) Basic type table
| Type | Size | Range / Use | Example |
|---|---|---|---|
| `int` | 4 B | ~±2.1 billion, general integer | `int n = 100;` |
| `long` | 8 B | ~±9.2×10¹⁸, large integer | `long big = 10_000_000_000L;` |
| `double` | 8 B | floating-point, general real number | `double pi = 3.14;` |
| `decimal` | 16 B | 28-digit precise real number, for money | `decimal won = 1500m;` |
| `bool` | 1 B | `true` / `false` | `bool ok = true;` |
| `char` | 2 B | single Unicode character | `char c = 'A';` |
| `string` | varies | text (reference type) | `string s = "hi";` |
Suffix `long` with `L` and `decimal` with `m`.
2) Value type vs reference type
- **Value types (struct, int, double, bool, char, enum...)**: the value itself is stored in the variable. **A copy duplicates the whole thing**.
- **Reference types (class, string, array...)**: the object lives on the heap and the variable only holds its address. **A copy shares the address**.
int a = 10;
int b = a; // value copy
b = 20;
// a == 10, b == 20 (independent)
int[] arr1 = [1, 2, 3];
int[] arr2 = arr1; // reference copy
arr2[0] = 99;
// arr1[0] == 99 (same array)3) `var`: type inference
`var` lets the compiler infer the type from the right-hand side. **The type doesn't disappear — it's just omitted**.
var name = "Alice"; // string
var age = 30; // int
var pi = 3.14; // doubleOnly allowed for local variables, and you must initialize it (`var x;` is invalid).
4) `const` and `readonly`
- `const`: a **compile-time constant**. Initialized at declaration and cannot be changed. Only basic types and `string` are allowed.
- `readonly`: can be **assigned exactly once at runtime**. Use for values set in the constructor.
const double Pi = 3.14159; // a value that never changes
// Pi = 3.14; // compile error5) Strings are immutable
`string` is a reference type, but **its contents cannot be changed**. `+=` or `Replace` returns a new string.
string s = "Hello";
s += ", World!"; // new string created, s now points to the new object6) Boxing
When you treat a value type as a reference type like `object`, **a copy is created on the heap**. It's slow and pressures the GC, so try to avoid it.
int n = 42;
object o = n; // boxing: new object created on the heap
int m = (int)o; // unboxingExamples
Example 1 — `Primitives/Program.cs`: tour of the basic types
int i = 100;
long l = 10_000_000_000L;
double d = 3.14;
decimal m = 1500.99m;
bool b = true;
char c = 'A';
string s = "hi";
Console.WriteLine($"int : {i} ({sizeof(int)} B)");
Console.WriteLine($"long : {l} ({sizeof(long)} B)");
Console.WriteLine($"double : {d} ({sizeof(double)} B)");
Console.WriteLine($"decimal: {m}");
Console.WriteLine($"bool : {b}, char: {c}, string: {s}");**Output**
int : 100 (4 B)
long : 10000000000 (8 B)
double : 3.14 (8 B)
decimal: 1500.99
bool : True, char: A, string: hi**Note:** `sizeof(decimal)` requires an unsafe context, so we skip it. Use `_` for digit grouping (`10_000_000_000`).
Example 2 — `ValueVsReference/Program.cs`: copy semantics compared
namespace CodingNow.Lecture.Basics02;
internal static class Program
{
public static void Main()
{
Point p1 = new(1, 2);
Point p2 = p1; // value copy
p2.X = 99;
Console.WriteLine($"p1=({p1.X},{p1.Y}) p2=({p2.X},{p2.Y})");
Box b1 = new() { Value = 10 };
Box b2 = b1; // reference copy
b2.Value = 99;
Console.WriteLine($"b1={b1.Value} b2={b2.Value}");
}
}
internal struct Point
{
public int X;
public int Y;
public Point(int x, int y) { X = x; Y = y; }
}
internal class Box
{
public int Value;
}**Output**
p1=(1,2) p2=(99,2)
b1=99 b2=99**Note:** `struct` is a value type so the two are independent; `class` is a reference type so they share the same object.
Example 3 — `VarConst/Program.cs`: `var`, `const`, `readonly`
var name = "Alice"; // inferred: string
var age = 30; // inferred: int
const double Pi = 3.14159;
const string Greet = "hi!";
Console.WriteLine($"{name}, {age} y/o, {Greet} (Pi={Pi})");
// Pi = 3.0; // compile error**Output**
Alice, 30 y/o, hi! (Pi=3.14159)**Note:** `var` is for readability — if the right-hand-side type isn't obvious, prefer an explicit type.
Example 4 — `StringBasics/Program.cs`: string immutability
string a = "Hello";
string b = a;
a += ", World!"; // new string created
Console.WriteLine($"a = {a}");
Console.WriteLine($"b = {b}"); // b still "Hello"
// concatenation methods
string c1 = string.Concat("value:", 42);
string c2 = $"value:{42}"; // string interpolation (recommended)
Console.WriteLine(c1);
Console.WriteLine(c2);**Output**
a = Hello, World!
b = Hello
value:42
value:42**Note:** Even after `a += "..."`, `b` still points to the original string. Strings are immutable, so sharing them is safe.
Full example code (src/)
src/Primitives/Primitives.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/Primitives/Program.cs
// basic types and sizes
int i = 100;
long l = 10_000_000_000L;
double d = 3.14;
decimal m = 1500.99m;
bool b = true;
char c = 'A';
string s = "hi";
Console.WriteLine($"int : {i} ({sizeof(int)} B)");
Console.WriteLine($"long : {l} ({sizeof(long)} B)");
Console.WriteLine($"double : {d} ({sizeof(double)} B)");
Console.WriteLine($"decimal: {m}");
Console.WriteLine($"bool : {b}, char: {c}, string: {s}");
src/StringBasics/Program.cs
// strings are immutable
string a = "Hello";
string b = a;
a += ", World!"; // only a points to a new object
Console.WriteLine($"a = {a}");
Console.WriteLine($"b = {b}");
// concatenation methods
string c1 = string.Concat("value:", 42);
string c2 = $"value:{42}"; // string interpolation (recommended)
Console.WriteLine(c1);
Console.WriteLine(c2);
src/StringBasics/StringBasics.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/ValueVsReference/Program.cs
namespace CodingNow.Lecture.Basics02;
internal static class Program
{
public static void Main()
{
// value type (struct): the whole value is copied
Point p1 = new(1, 2);
Point p2 = p1;
p2.X = 99;
Console.WriteLine($"p1=({p1.X},{p1.Y}) p2=({p2.X},{p2.Y})");
// reference type (class): the address is shared
Box b1 = new() { Value = 10 };
Box b2 = b1;
b2.Value = 99;
Console.WriteLine($"b1={b1.Value} b2={b2.Value}");
}
}
internal struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
}
internal class Box
{
public int Value;
}
src/ValueVsReference/ValueVsReference.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/VarConst/Program.cs
// var: compiler infers the type from the right-hand side
var name = "Alice"; // string
var age = 30; // int
// const: compile-time constant (no later mutation)
const double Pi = 3.14159;
const string Greet = "hi!";
Console.WriteLine($"{name}, {age} y/o, {Greet} (Pi={Pi})");
// Pi = 3.0; // compile error
src/VarConst/VarConst.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Common Mistakes
- Overflowing `int` (about ±2.1 billion) — use `long` for big numbers.
- Using `double` for money — floating-point errors. **Always use `decimal`**.
- Using `var x;` without initialization — compile error.
- Accumulating a `string` with `+=` in a loop creates a new object each iteration. For large volumes use `StringBuilder` (see lecture 16).
- Confusing `const` and `readonly` — `const` is a compile-time constant, `readonly` is set once at runtime.
Summary
- Integers: `int`/`long`. Reals: `double` (science) / `decimal` (money)
- Value types are copied whole; reference types share the address
- `var` is type inference for convenience, `const` is absolute immutability
- `string` is a reference type but immutable — safe to share
- Storing a value type in `object` causes boxing → avoid where possible
Practice
**Practice - 02. Variables and Types**
Problem 1 — Profile card
- Project folder: `Homework01/`
- Key concepts: variable declaration, picking the right type, string interpolation
Requirements
- Store each piece of data in an appropriately-typed variable
- name (`string`)
- age (`int`)
- height in cm (`double`)
- is-student (`bool`)
- Print each on its own line
Expected output
=== Profile ===
Name: Alex
Age: 25
Height: 172.5cm
Student: TrueHints
- For decimals like height use `double`
- Printing a `bool` gives `True` / `False`
Problem 2 — Arithmetic on two integers
- Project folder: `Homework02/`
- Key concepts: `Console.ReadLine`, `int.Parse`, arithmetic operators
Requirements
- Read two integers from the user
- Print their sum, difference, product, quotient, and remainder
Expected output
First integer: 10
Second integer: 3
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
10 / 3 = 3
10 % 3 = 1Hints
- Convert with `int a = int.Parse(Console.ReadLine()!);`
- `!` is the null-forgiving operator — tells the compiler "not null" (more in lecture 3)
- Integer `/` is the quotient, `%` is the remainder
Check your answer
Try it yourself, then compare against the [`answer/`](./answer/) folder.
Answer (answer/)
homework/answer/Homework01/Homework01.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
homework/answer/Homework01/Program.cs
// Profile card
string name = "Alex";
int age = 25;
double height = 172.5;
bool isStudent = true;
Console.WriteLine("=== Profile ===");
Console.WriteLine($"Name: {name}");
Console.WriteLine($"Age: {age}");
Console.WriteLine($"Height: {height}cm");
Console.WriteLine($"Student: {isStudent}");
homework/answer/Homework02/Homework02.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Basics02</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
homework/answer/Homework02/Program.cs
// Arithmetic on two integers
Console.Write("First integer: ");
int a = int.Parse(Console.ReadLine()!);
Console.Write("Second integer: ");
int b = int.Parse(Console.ReadLine()!);
Console.WriteLine($"{a} + {b} = {a + b}");
Console.WriteLine($"{a} - {b} = {a - b}");
Console.WriteLine($"{a} * {b} = {a * b}");
Console.WriteLine($"{a} / {b} = {a / b}");
Console.WriteLine($"{a} % {b} = {a % b}");
Try It Yourself
cd src/Primitives && dotnet run
cd ../ValueVsReference && dotnet run
cd ../VarConst && dotnet run
cd ../StringBasics && dotnet runNext Lecture
[03_Operators_and_Expressions](../03_%EC%97%B0%EC%82%B0%EC%9E%90%EC%99%80_%ED%91%9C%ED%98%84%EC%8B%9D/) — Tools to compute and compare with variables.
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗