Type Casting & Boxing/Unboxing

Real programs constantly move data between types — a user types "42" as text and you need the number; a calculation produces a double and you need a whole count. This lesson covers safe and unsafe conversions, the difference between Parse and TryParse , and the subtle world of boxing and unboxing that trips up many intermediate developers.

Learn Type Casting & Boxing/Unboxing in our free C# course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free C# course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

Casting is like pouring liquid between containers . Pouring a small glass into a large jug ( int → double ) is always safe — it just fits. Pouring the big jug back into the small glass ( double → int ) might overflow, so C# makes you confirm with (int) that you accept spilling the extra. Boxing is putting that glass inside a sealed parcel (an object ) so it can travel through a system that only handles parcels; unboxing is opening the parcel — and you must know exactly what glass to expect.

1. Implicit vs Explicit Casting

When a conversion can never lose data — a smaller type going into a larger one — C# does it for you automatically ( implicit ). When data could be lost, you must spell out the target type in parentheses ( explicit ), which is your signature accepting the consequences. The classic gotcha: (int) on a decimal truncates (chops the fraction), it does not round.

2. Strings ↔ Numbers

Text and numbers are completely different types, so you can't cast between them with (int) — you convert. Going text → number uses Parse (throws on bad input) or TryParse (safe). Going number → text uses ToString , optionally with a format string like "C" or "F2" . For anything a user typed, always reach for TryParse .

Your turn. The two strings below came from a form. Convert each to the right number type, then run the calculation.

3. Boxing & Unboxing

Because every type in C# ultimately derives from object , a value type like int can be stored in an object variable. Doing so boxes it: the value is copied onto the heap inside a little wrapper. Reading it back out unboxes it, and you must cast to the exact original type — unboxing an int as a long throws at runtime even though the number would fit.

Boxing isn't free. Each box is a heap allocation , and the garbage collector later has to clean it up. In a tight loop that boxes millions of values, this becomes a real bottleneck — the classic example was the old non-generic ArrayList , which stored everything as object and boxed every int you added.

This is exactly why generics exist. stores int values directly with no boxing, so it's both faster and type-safe. Whenever you see code converting values to object in a loop, suspect accidental boxing and prefer a generic collection.

Here's the pattern you'll use constantly: take messy, possibly-invalid text and process only the valid parts without ever crashing.

These six lines safely convert text to a number and print a doubled result. Put them in the order that compiles and prints Doubled: 50 .

Why: text must be declared before TryParse reads it. The if declares n via out , so the WriteLine using n must follow it. The else must come immediately after the if body — an else with no preceding if is a syntax error.

7 — casting double to int truncates the fraction; it does not round to 8.

15 — 5 is boxed into box , then unboxed back to int as 5 , and 5 + 10 = 15 .

False 0 — "12abc" isn't a valid integer, so TryParse returns false and sets r to its default, 0 .

Combine everything: parse only valid text, track a running total and count, and divide carefully to avoid integer division. The outline is in the comments.

Practice quiz

An implicit cast in C# happens automatically when:

  • The conversion can never lose data, e.g. int to double
  • You write the (type) syntax explicitly
  • Converting any number to a string
  • Whenever two types share a base class

Answer: The conversion can never lose data, e.g. int to double. Implicit casts are allowed only when no data can be lost, such as a smaller type (int) widening into a larger one (double or long).

What does the explicit cast (int)3.99 evaluate to?

  • 4
  • 3
  • 3.99
  • A compile error

Answer: 3. Casting a double to an int truncates (drops the fractional part); it does not round. So (int)3.99 is 3.

What is (int)(-2.7) in C#?

  • -3
  • -2
  • 2
  • 0

Answer: -2. Truncation chops the fractional part toward zero, so -2.7 becomes -2, not -3.

Which method should you use to convert user-supplied text to a number without risking a crash?

  • int.Parse
  • int.TryParse
  • (int) cast
  • Convert.ToDouble

Answer: int.TryParse. TryParse returns false on bad input instead of throwing, so user input can be handled gracefully. Parse throws a FormatException.

What does int.Parse("12x") do at runtime?

  • Returns 12
  • Returns 0
  • Throws a FormatException
  • Returns null

Answer: Throws a FormatException. Parse throws a FormatException when the text is not a valid integer. TryParse would instead return false.

After bool ok = int.TryParse("abc", out int r); what are ok and r?

  • true and 0
  • false and 0
  • false and -1
  • true and abc

Answer: false and 0. TryParse fails on "abc", so it returns false and sets the out variable to its default, 0.

What is boxing in C#?

  • Wrapping a value type inside an object on the heap
  • Converting a string to a number
  • Casting a double to an int
  • Splitting an array into segments

Answer: Wrapping a value type inside an object on the heap. Boxing copies a value type (like int) into an object on the heap so it can be treated as a reference type.

Given object boxed = 5; which unboxing line is valid at runtime?

  • long x = (long)boxed;
  • double x = (double)boxed;
  • int x = (int)boxed;
  • short x = (short)boxed;

Answer: int x = (int)boxed;. A boxed value must be unboxed to its exact original type. The 5 was boxed as an int, so only (int)boxed succeeds; the others throw InvalidCastException.

Why is boxing best avoided inside a tight loop?

  • It rounds numbers incorrectly
  • Each box is a heap allocation that adds GC pressure
  • It always throws an exception
  • It converts ints to strings

Answer: Each box is a heap allocation that adds GC pressure. Every box is a separate heap allocation the garbage collector must later clean up, which is slow in hot paths. Generics like List<int> avoid it.

To round 3.99 to the nearest whole number instead of truncating, you should use:

  • (int)3.99
  • Math.Round(3.99)
  • Math.Floor(3.99)
  • int.Parse("3.99")

Answer: Math.Round(3.99). Math.Round rounds to the nearest whole number (giving 4 here). An (int) cast and Math.Floor would both truncate to 3.