← Back to C# series
🟣
Basics
Basics · Prerequisite: previous lecture

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.

C#.NET 8basicsvariables and types
Duration
~1-1.5 hours
Level
📊 Beginner
Prerequisite
🎯 Previous lecture or equivalent
OUTCOME
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

TypeSizeRange / UseExample
`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 Bfloating-point, general real number`double pi = 3.14;`
`decimal`16 B28-digit precise real number, for money`decimal won = 1500m;`
`bool`1 B`true` / `false``bool ok = true;`
`char`2 Bsingle Unicode character`char c = 'A';`
`string`variestext (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**.
csharp
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**.

csharp
var name = "Alice";   // string
var age = 30;         // int
var pi = 3.14;        // double

Only 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.
csharp
const double Pi = 3.14159;        // a value that never changes
// Pi = 3.14;  // compile error

5) Strings are immutable

`string` is a reference type, but **its contents cannot be changed**. `+=` or `Replace` returns a new string.

csharp
string s = "Hello";
s += ", World!";   // new string created, s now points to the new object

6) 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.

csharp
int n = 42;
object o = n;     // boxing: new object created on the heap
int m = (int)o;   // unboxing

Examples

Example 1 — `Primitives/Program.cs`: tour of the basic types

csharp
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**

text
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

csharp
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**

text
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`

csharp
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**

text
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

csharp
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**

text
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

xml
<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

csharp
// 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

csharp
// 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

xml
<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

csharp
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

xml
<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

csharp
// 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

xml
<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

  1. Overflowing `int` (about ±2.1 billion) — use `long` for big numbers.
  2. Using `double` for money — floating-point errors. **Always use `decimal`**.
  3. Using `var x;` without initialization — compile error.
  4. Accumulating a `string` with `+=` in a loop creates a new object each iteration. For large volumes use `StringBuilder` (see lecture 16).
  5. 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

text
=== Profile ===
Name: Alex
Age: 25
Height: 172.5cm
Student: True

Hints

  • 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

text
First integer: 10
Second integer: 3
10 + 3 = 13
10 - 3 = 7
10 * 3 = 30
10 / 3 = 3
10 % 3 = 1

Hints

  • 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

xml
<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

csharp
// 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

xml
<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

csharp
// 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

bash
cd src/Primitives && dotnet run
cd ../ValueVsReference && dotnet run
cd ../VarConst && dotnet run
cd ../StringBasics && dotnet run

Next 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.

Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub ↗