Static Members and Extension Methods
static Fields and Methods
static members belong to the type itself rather than to any instance. All instances share the same static field. Static methods are called via ClassName.Member without creating an object.
Example
class Counter
{
public static int TotalCount = 0;
public int InstanceId;
public Counter(int id)
{
InstanceId = id;
TotalCount++;
}
public static void Report()
{
Console.WriteLine($"{TotalCount} instances created");
}
}
Counter a = new Counter(1);
Counter b = new Counter(2);
Counter.Report();
Console.WriteLine(Counter.TotalCount);
2 instances created
2
static methods cannot use this and cannot directly access instance members — they can only access other static members.
Static Constructors
A static constructor runs automatically once when the class is first accessed, and only once. It cannot have access modifiers or parameters, and is commonly used to initialize static fields.
Example
class Config
{
public static readonly DateTime StartTime;
static Config()
{
StartTime = DateTime.Now;
Console.WriteLine("Static constructor executed");
}
}
Console.WriteLine("Preparing to access Config");
Console.WriteLine(Config.StartTime);
Console.WriteLine(Config.StartTime);
Preparing to access Config
Static constructor executed
2026/06/28 10:00:00
2026/06/28 10:00:00
static Classes (Utility Class Pattern)
A class declared with static class cannot be instantiated or inherited. All members must be static, making it suitable for encapsulating utility methods.
Example
static class MathHelper
{
public static double Square(double x) => x * x;
public static double Hypotenuse(double a, double b) => Math.Sqrt(Square(a) + Square(b));
}
Console.WriteLine(MathHelper.Square(3));
Console.WriteLine(MathHelper.Hypotenuse(3, 4));
9
5
new MathHelper() causes a compile error — static classes cannot be instantiated.
const vs static readonly
| Feature | const |
static readonly |
|---|---|---|
| When assigned | Compile time | Runtime |
| Value types | Built-in types only | Any type |
| Mutability | Immutable | Immutable after assignment in constructor |
Example
class Settings
{
public const int MaxRetry = 3;
public static readonly DateTime LaunchTime;
static Settings()
{
LaunchTime = DateTime.Now;
}
}
Console.WriteLine(Settings.MaxRetry);
Console.WriteLine(Settings.LaunchTime);
3
2026/06/28 10:00:00
const values are embedded in the caller's assembly at compile time. If a const is modified, all referencing assemblies must be recompiled. static readonly is read at runtime, making it safer.
Extension Methods
Extension methods "add" methods to an existing type without modifying it. They are defined in a static class, and the first parameter is prefixed with the this keyword, allowing them to be called as if they were instance methods.
Example
static class StringExt
{
public static bool IsEmpty(this string s) => s.Length == 0;
public static string Repeat(this string s, int count)
{
var sb = new StringBuilder();
for (int i = 0; i < count; i++) sb.Append(s);
return sb.ToString();
}
}
Console.WriteLine("hello".IsEmpty());
Console.WriteLine("ab".Repeat(3));
False
ababab
s.IsEmpty() into StringExt.IsEmpty(s). Instance methods take precedence over extension methods.
Extension Methods in Practice (LINQ Fundamentals)
LINQ's fluent syntax is built on extension methods. Where, Select, OrderBy, and others in System.Linq.Enumerable are all extension methods on IEnumerable<T>.
Example
static class EnumerableExt
{
public static IEnumerable<T> MyWhere<T>(this IEnumerable<T> source, Func<T, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item)) yield return item;
}
}
}
int[] nums = { 1, 2, 3, 4, 5, 6 };
var even = nums.MyWhere(n => n % 2 == 0);
Console.WriteLine(string.Join(", ", even));
2, 4, 6
partial Classes
The partial keyword allows a class definition to be split across multiple files, which are merged into a single complete class at compile time. This is commonly used to separate auto-generated code from hand-written code.
Example
partial class User
{
public string Name { get; set; }
public User(string name) => Name = name;
}
partial class User
{
public void Greet() => Console.WriteLine($"Hello, {Name}");
}
var u = new User("Alice");
u.Greet();
Hello, Alice
partial Methods
A partial method is declared in one part of a partial class and optionally implemented in another part. If not implemented, the compiler removes the call site — zero overhead. Starting with C# 9, partial methods no longer have signature restrictions.
Example
partial class Order
{
public int Amount { get; set; }
partial void OnCreated();
public Order(int amount)
{
Amount = amount;
OnCreated();
}
}
partial class Order
{
partial void OnCreated() => Console.WriteLine("Order created");
}
var o = new Order(100);
Console.WriteLine(o.Amount);
Order created
100
OnCreated implementation from the second partial class, the program still compiles, and the call site is automatically removed by the compiler.
❓ FAQ
📖 Summary
staticfields are shared across all instances;staticmethods are called via the class name- Static constructors execute once when the class is first accessed, used to initialize static members
static classcannot be instantiated or inherited — ideal for utility classesconstis a compile-time constant;static readonlyis a runtime constant- Extension methods use the
thisparameter to add methods to existing types — the foundation of LINQ partialclasses split definitions across multiple files, merged at compile timepartialmethods provide optional hooks — unimplemented calls are removed by the compiler
📝 Exercises
- Write a
static class ArrayHelperwithMax(int[] arr)andAverage(int[] arr)static methods, and test them in Main - Write an extension method
MySumforIEnumerable<int>that calculates the sum of an integer sequence without using LINQ - Create a
partial class Logger— in one part, declarepartial void OnLog(string message)and aLog(string msg)method (which calls OnLog internally); in the other part, implement OnLog to write to the console - Define a
constfield and astatic readonlyfield, and write code to verify that const is replaced at compile time while static readonly is read at runtime (hint: reference them from another assembly and observe the behavior after modification)



