Codectionary / Developer documentation / C#

Variables & Data Types

C# is a statically-typed language, meaning every variable's type is fixed at compile time. Built-in value types include int, double, decimal, bool, and char, while string and object are reference types. The var keyword lets the compiler infer a variable's type from its initializer, but the variable is still strongly typed underneath - it just saves you from writing the type name explicitly.

Read the syntax

A declaration names a type, then a variable, and normally an initial value: int age = 21;. C# checks assignments against the variable’s type before the program runs; var asks the compiler to infer that type, not to make it dynamic.

Use a decimal literal with an m suffix for base-ten arithmetic, a single quoted character for char, and double quoted text for string. A ? on a value type permits null; ?? supplies a fallback when the value is null.

Syntax

type variableName = value;

Breaking down the syntax

int
An integer type.
string
A text reference type.
var
Infers a local variable type from its initializer.

How it works

A C# local variable has a type that controls which values it can hold. var asks the compiler to infer that type from its initial value.

Declare

Choose a name and type, or infer it.

Assign

Supply a compatible value.

Use

Operations are checked against that type.

Examples

A small working example

Follow the values through this example, then change one input.

using System;
class Program {
    static void Main() {
        int lessons = 3;
        string language = "C#";
        Console.WriteLine($"{language}: {lessons} lessons");
    }
}
  1. lessons stores an int.
  2. language stores text.
  3. The interpolated string inserts both values.

Declaring Variables

Creating variables of common built-in types.

int age = 21;
double gpa = 3.8;
decimal price = 19.99m;   // m suffix for decimal - ideal for money
char grade = 'A';
bool isStudent = true;
string name = "John";

Console.WriteLine($"{name}, {age}, {gpa}, {grade}, {isStudent}");
  1. Creating variables of common built-in types.
  2. A declaration names a type, then a variable, and normally an initial value: int age = 21;. C# checks assignments against the variable’s type before the program runs; var asks the compiler to infer that type, not to make it dynamic.
  3. The six declarations hold different kinds of values. Interpolation inserts five of them into one console line; price is declared but is not printed. The m suffix makes 19.99 a decimal rather than a double.

Implicit Typing with var

The compiler infers the type from the right-hand side - the variable is still strongly typed, just without an explicit type name.

var count = 10;         // inferred as int
var total = 19.99;      // inferred as double
var label = "Total: ";  // inferred as string

// count = "text";  // Error! count is still an int under the hood
Console.WriteLine(label + total);
  1. The compiler infers the type from the right-hand side - the variable is still strongly typed, just without an explicit type name.
  2. A declaration names a type, then a variable, and normally an initial value: int age = 21;. C# checks assignments against the variable’s type before the program runs; var asks the compiler to infer that type, not to make it dynamic.
  3. count remains an int, so uncommenting the string assignment produces a compile-time error. The final line concatenates label and total and prints Total: 19.99 under a culture that uses a dot for decimals.

Constants with const and readonly

const values are fixed at compile time; readonly values can be set once, at declaration or in a constructor.

const double Pi = 3.14159;         // must be assigned a compile-time constant
Console.WriteLine(Pi);

class Circle
{
    public readonly double Radius;  // can be set in the constructor, not after

    public Circle(double radius)
    {
        Radius = radius;
    }
}
  1. const values are fixed at compile time; readonly values can be set once, at declaration or in a constructor.
  2. A declaration names a type, then a variable, and normally an initial value: int age = 21;. C# checks assignments against the variable’s type before the program runs; var asks the compiler to infer that type, not to make it dynamic.
  3. Pi can be printed because its value is known at compile time. Circle is only declared here: no Circle object is created, so Radius is never printed; its constructor can assign that readonly field.

Nullable Value Types

Value types like int normally can't be null - appending ? makes them nullable.

int? age = null;          // nullable int
double? score = 85.5;

if (age.HasValue)
{
    Console.WriteLine(age.Value);
}
else
{
    Console.WriteLine("Age not set");
}

int actualAge = age ?? 0;  // null-coalescing: use 0 if age is null
Console.WriteLine(actualAge);
  1. Value types like int normally can't be null - appending ? makes them nullable.
  2. A declaration names a type, then a variable, and normally an initial value: int age = 21;. C# checks assignments against the variable’s type before the program runs; var asks the compiler to infer that type, not to make it dynamic.
  3. age.HasValue is false, so the else branch prints Age not set. The ?? expression then chooses 0 and prints it; accessing age.Value without the preceding check would throw.

Best practices

  • Use PascalCase for public members and camelCase for local variables and private fields, following standard C# naming conventions
  • Use var when the type is obvious from the right-hand side (var list = new List<string>();), but prefer an explicit type when it improves readability
  • Use decimal, never double or float, for money and other values where exact precision matters - double introduces small rounding errors
  • Use nullable value types (int?) and the null-coalescing operator (??) to handle "no value" cases explicitly, rather than relying on magic sentinel numbers

Runtime & versions

.NET runtime. Feature availability depends on the language and runtime version used by your project; consult the official reference below.

C# language reference

When should I use this?

Name intermediate results and application state with types that communicate their meaning.

Common mistakes

A common trap

var inferred int; it does not make the variable dynamically typed.

Incorrect

var count = 1;
count = "two";

Corrected

var count = 1;
count = 2;

Compare approaches

  • Explicit type: Make the type visible at the declaration.
  • var: Use inference when the initializer makes the type clear.

Explore deeper

decimal literals

Use the m suffix for decimal literals, for example 12.50m. Decimal arithmetic is often useful for base-10 financial values; rounding rules still need an explicit application policy.

Specifications & further reading