Site

Variables — C# Types and Variables

Tutorial 3.0  •  C# / Learn

3.0 What This Teaches

This tutorial covers how C# handles variables and types:

3.1 Declaring Variables

C# is statically typed - every variable has a fixed type decided at compile time. Declare a variable with an explicit type or with var:
int count = 10;            // explicit type
double ratio = 3.14;       // explicit type
var name = "Alice";        // compiler infers string
var active = true;         // compiler infers bool
var is not dynamic typing - the type is still fixed at compile time. It just lets the compiler infer it from the right-hand side. Use var when the type is obvious from context; write the type explicitly when it aids clarity.

3.2 Value Types

Value types hold their data directly. Assigning one to another copies the data. Common value types:
TypeSizeRange / Notes
int32-bit-2,147,483,648 to 2,147,483,647
long64-bitVery large integers
double64-bit~15 significant decimal digits
float32-bit~7 significant decimal digits
decimal128-bitExact decimal; use for money
bool1 bytetrue or false
char16-bitA single UTF-16 code unit; single quotes: 'A'

3.3 Reference Types

Reference types store a reference to data on the heap. Assigning one to another copies the reference, not the data - both variables point to the same object.
string greeting = "Hello";     // immutable string
string copy = greeting;        // copy points to same string object
object anything = 42;          // object holds any type
string is special - it is a reference type but behaves like a value type because strings in C# are immutable. Every modification creates a new string object.

3.4 const and readonly

Use const for values fixed at compile time. Use readonly for values set once at runtime (in a constructor or field initializer):
const double Pi = 3.14159265358979;
const int MaxRetries = 3;

readonly DateTime startTime = DateTime.Now;  // set at runtime, then fixed
const values are inlined by the compiler - they never occupy memory at runtime. readonly fields occupy memory but cannot be reassigned after the constructor finishes.

3.5 Nullable Types

By default, value types cannot be null. Append ? to allow null:
int? age = null;           // nullable int
string? name = null;       // nullable reference type (requires Nullable enabled)

int displayAge = age ?? 0;           // ?? returns right side if left is null
string displayName = name ?? "Guest";

int length = name?.Length ?? 0;      // ?. short-circuits on null
With Nullable enabled in the project, the compiler warns when you dereference a nullable reference without a null check.

3.6 Type Conversions

Implicit conversions happen automatically when no data is lost. Explicit casts require your instruction because data may be lost:
int i = 42;
long l = i;        // implicit: int always fits in long
double d = i;      // implicit: int always fits in double

double pi = 3.14;
int truncated = (int)pi;           // explicit cast: truncates to 3

string s = "123";
int parsed = int.Parse(s);         // throws if invalid
bool ok = int.TryParse(s, out int result);  // safe: returns false if invalid

3.7 Example - All Together

// Variables - demonstrates C# types, var, nullable, and conversion.
int score = 95;
double average = 88.5;
bool passed = score >= 60;
char grade = passed ? 'A' : 'F';
string? comment = null;

Console.WriteLine($"Score: {score}, Average: {average:F1}");
Console.WriteLine($"Passed: {passed}, Grade: {grade}");
Console.WriteLine($"Comment: {comment ?? "none"}");

const int MaxScore = 100;
double percent = (double)score / MaxScore * 100;
Console.WriteLine($"Percent: {percent:F1}%");
Expected output:
Score: 95, Average: 88.5
Passed: True, Grade: A
Comment: none
Percent: 95.0%

3.8 Exercise

Exercise
  • Declare an int for your age, a double for your height in meters, a string for your name, and a bool for whether you are a student. Print all four.
  • Declare an int? set to null. Use ?? to display 0 as a default when printing.
  • Parse the string "42" to an int using int.TryParse. Print whether it succeeded and the result.

3.9 Common Mistakes

Integer overflow

int max = int.MaxValue;
int overflow = max + 1;   // wraps to int.MinValue in unchecked context
int overflows silently by default. Use long when values might exceed 2,147,483,647, or wrap in a checked block to catch it.

Using double for money

double price = 0.1 + 0.2;
Console.WriteLine(price);   // 0.30000000000000004
Binary floating-point cannot represent all decimal fractions exactly. Use decimal for financial calculations.

NullReferenceException on uninitialized reference

Calling a method on a null reference throws NullReferenceException. With nullable types enabled, the compiler warns about potential null dereferences. Heed those warnings.

3.10 Key Terms

TermMeaning
value typeType whose data lives directly in the variable (int, double, bool, struct)
reference typeType whose variable holds a reference to heap data (class, string, array)
varKeyword that lets the compiler infer the type; still statically typed
constCompile-time constant; inlined by the compiler
readonlyRuntime constant; set once in a constructor or initializer
nullable (int?)Value type extended to allow null values
?? operatorReturns the right operand when the left is null
decimal128-bit exact decimal type; use for money and financial math