Static Members
Most members belong to an individual object: each Dog has its own name. A static member belongs to the class itself and is shared by every instance — or used without any instance at all, like Math.Sqrt or Console.WriteLine. This lesson covers static fields, methods, properties, classes and constructors, plus const versus readonly.
Static fields: shared data
A static field exists once, no matter how many objects there are. Here it counts how many tickets have been issued and gives each one a unique number:
var t1 = new Ticket("Ana"); var t2 = new Ticket("Ben"); var t3 = new Ticket("Cy"); Console.WriteLine(t1); Console.WriteLine(t3); Console.WriteLine($"Issued: {Ticket.IssuedCount}"); class Ticket { private static int s_nextNumber = 1000; public static int IssuedCount { get; private set; } public int Number { get; } public string Holder { get; } public Ticket(string holder) { Holder = holder; Number = s_nextNumber++; IssuedCount++; } public override string ToString() => $"#{Number} {Holder}"; }
#1000 Ana #1002 Cy Issued: 3
Static members are accessed through the class name: Ticket.IssuedCount, not t1.IssuedCount. (The s_ prefix for private static fields is a common .NET convention.)
Static methods
A static method doesn't work on a particular object, so it can't use instance fields or this. It's the right choice for utilities that only depend on their parameters, and for factory methods that create objects:
var a = Money.FromCents(1999); var b = Money.Parse("$5.25"); Console.WriteLine(a); Console.WriteLine(b); Console.WriteLine(Money.Add(a, b)); class Money { public decimal Amount { get; } private Money(decimal amount) => Amount = amount; public static Money FromCents(long cents) => new(cents / 100m); public static Money Parse(string text) => new(decimal.Parse(text.TrimStart('$'))); public static Money Add(Money x, Money y) => new(x.Amount + y.Amount); public override string ToString() => $"${Amount:F2}"; }
$19.99 $5.25 $25.24
The constructor is private, so the only way to get a Money is through the well-named static methods.
A static method can't touch instance members, because there's no "current object":
Counter.Reset(); class Counter { private int _count; public static void Reset() => _count = 0; }
Program.cs(6,35): error CS0120: An object reference is required for the non-static field, method, or property 'Counter._count'
Static classes
A class marked static can only contain static members and can't be instantiated. It's a home for related helper functions, like Math, Console, File and Path:
Console.WriteLine(Units.KmToMiles(42.195)); Console.WriteLine(Units.KgToPounds(70)); static class Units { private const double MilesPerKm = 0.621371; private const double PoundsPerKg = 2.20462; public static double KmToMiles(double km) => Math.Round(km * MilesPerKm, 2); public static double KgToPounds(double kg) => Math.Round(kg * PoundsPerKg, 1); }
26.22 154.3
using static
using static imports a class's static members so you can call them without the class name. Use it sparingly, where it really aids readability, such as maths-heavy code:
using static System.Math; double hypotenuse = Sqrt(Pow(3, 2) + Pow(4, 2)); Console.WriteLine(hypotenuse); Console.WriteLine(Round(PI * Pow(2, 2), 3));
5 12.566
const vs static readonly
Both create values that don't change, but they work differently:
const— a compile-time constant. Only numbers,bool,char, strings and enums. The value is copied into every place that uses it.static readonly— set once at run time, when the class is first used. Any type is allowed, and the value can be computed.
Console.WriteLine(AppInfo.Name); Console.WriteLine(AppInfo.SupportedLanguages.Length); Console.WriteLine(AppInfo.StartedAt.Year > 2000); static class AppInfo { public const string Name = "Planner"; public static readonly string[] SupportedLanguages = ["en", "es", "fr"]; public static readonly DateTime StartedAt = DateTime.Now; }
Planner 3 True
readonly only stops the field being reassigned; the array it refers to could still be modified. For truly fixed lists, expose an immutable collection.
Static constructors
A static constructor runs once, automatically, before the class is first used. It's for setting up static data that needs more than a one-line initialiser:
Console.WriteLine("Program starts"); Console.WriteLine(Lookup.Squares[12]); Console.WriteLine(Lookup.Squares[99]); static class Lookup { public static readonly int[] Squares; static Lookup() { Console.WriteLine("Building lookup table..."); Squares = new int[100]; for (int i = 0; i < Squares.Length; i++) Squares[i] = i * i; } }
Program starts Building lookup table... 144 9801
When to use static
- Yes: pure helper functions, factory methods, constants, and data that is genuinely shared.
- Careful: static mutable state (like a static list everyone adds to) is effectively a global variable. It makes code harder to test, and it's shared between threads, which can cause bugs (lesson 58).
Try it yourself
Give each Invoice an automatic number in the format INV-0001, and add a static method that returns how many invoices exist.
INV-0001 INV-0002 INV-0003 Created: 3, total value 495.5