static KeywordUse the static keyword. Create static methods, static classes and static constructors.
This page was last reviewed on Apr 16, 2024.
Static. Static things are singular—a static class is only present in one place in a program. This C# keyword can be placed on classes, methods and fields.
Static methods can be placed upon any type. To call a static method, we do not need an instance of the type—it can be accessed directly.
Global Variable
First example. Classes are created as instances. But static fields are part of no instance. Static things exist in a separate, singular place.
Info In a static class, all fields and methods must also be static. This is a useful restriction—it helps keep code maintainable.
Step 1 In this program, we see that the static field is displayed. In the static class, the field has been initialized to 5.
Step 2 The field is set to int.MaxValue, and displayed again. Its value has been changed to a new one.
using System; static class Mountain { public static int _value = 5; } class Program { static void Main() { // Step 1: print the value of the Mountain field. Console.WriteLine("STATIC FIELD: " + Mountain._value); // Step 2: change the value, then print it again. Mountain._value = int.MaxValue; Console.WriteLine("STATIC FIELD: " + Mountain._value); } }
Static methods. These are called with the type name. No instance is required—this makes them slightly faster. Static methods can be public or private.
Info Static methods use the static keyword, usually as the first keyword or the second keyword after public.
Warning A static method cannot access non-static class level members. It has no "this" pointer.
Detail An instance method can access those members, but must be called through an instantiated object. This adds indirection.
using System; class Program { static void MethodA() { Console.WriteLine("Static method"); } void MethodB() { Console.WriteLine("Instance method"); } static char MethodC() { Console.WriteLine("Static method"); return 'C'; } char MethodD() { Console.WriteLine("Instance method"); return 'D'; } static void Main() { // ... Call the 2 static methods on the Program type. Program.MethodA(); Console.WriteLine(Program.MethodC()); // ... Create a new Program instance and call the 2 instance methods. Program programInstance = new Program(); programInstance.MethodB(); Console.WriteLine(programInstance.MethodD()); } }
Static method Static method C Instance method Instance method D
Static property. These are similar to static methods. In the metadata, properties have the word "get_" or "set_" prefixed to their identifiers.
Tip We use static properties in the same way as static methods. Properties show the same performance levels of methods.
Info Some static properties, like DateTime.Now, can be expensive—this is usually considered a design error.
using System; static class Settings { public static int DayNumber { get { return DateTime.Today.Day; } } public static string DayName { get { return DateTime.Today.DayOfWeek.ToString(); } } public static bool Finished { get; set; } } class Program { static void Main() { // Read the static properties. Console.WriteLine(Settings.DayNumber); Console.WriteLine(Settings.DayName); // Change the value of the static bool property. Settings.Finished = true; Console.WriteLine(Settings.Finished); } }
13 Sunday True
Static field. Static methods in a class cannot directly access instance fields in that same class. But they can access static fields. An instance method can access a static field.
Next A static field does not have to be a value type. It can instead be a reference.
Note The reference is initialized automatically to null. We can assign it to a new instance of the class.
using System; class Test { public int _value; } class Program { static Test _field; static void Main() { // Assign static field to new class instance. Program._field = new Test(); // Assign an instance field of the object. Program._field._value = 1; // Display it. Console.WriteLine(Program._field._value); } }
Static class. A static class is never instantiated. The static keyword on a class enforces that a type not be created with a constructor. This eliminates misuse of the class.
Note A static class cannot have non-static members. All methods, fields and properties in it must also be static.
Detail There are 2 classes in this program: the Program class, which is not static, and the Perl class, which is static.
And We cannot create a new instance of Perl using a constructor. Trying to do so results in an error.
Finally Inside the Perl class, we use static on all fields and methods. Instance members cannot be contained in a static class.
using System; class Program { static void Main() { // Cannot declare a variable of type Perl. // This won't blend. // Perl perl = new Perl(); // Program is a regular class so you can create it. Program program = new Program(); // You can call static methods inside a static class. Perl._ok = true; Perl.Blend(); } } static class Perl { // Cannot declare instance members in a static class! // int _test; // This is ok. public static bool _ok; // Can only have static methods in static classes. public static void Blend() { Console.WriteLine("Blended"); } }
Static constructor. A static constructor initializes static fields. It runs at an indeterminate time before those fields are used. Static constructors impose some overhead.
Note A static constructor is sometimes called a type initializer. It initializes fields before accesses.
Note 2 Instances are not the same as types. An instance is a specific object of the type.
using System; static class Bird { public static int _elevation; static Bird() { // The static constructor can call methods. _elevation = Fly(10); } static int Fly(int multiplier) { return Environment.TickCount * multiplier; } } class Program { static void Main() { // The static constructor always runs before we access elevation. Console.WriteLine("ELEVATION: {0}", Bird._elevation); } }
ELEVATION: 37831250
Using static. We can use a static class in a program to simplify our syntax. Here we use the static System.Math and System.Console classes.
Detail We can invoke Math.Abs with just the "Abs" function name. The static System.Math provides this.
Detail We avoid specifying Console in the WriteLine call. The "using static System.Console" directive is needed.
using static System.Math; using static System.Console; class Program { static void Main() { int number = -100; // Use Abs from static System.Math. int result = Abs(number); // Use WriteLine from static System.Console. WriteLine(result); } }
Singleton example. The singleton design pattern is an interface. It allows a class to enforce that it is only allocated once. In C#, singletons can be implemented as static fields.
Detail Here the readonly and static keywords are used. Readonly allows thread-safety, and that means it can be only allocated once.
Part 1 The public Instance property is used by callers to get the singleton instance.
Part 2 We use the Singleton instance by calling the Message() method. This writes some text to the console.
using System; class Program { static void Main() { // Part 1: initialize singleton. var instance = Singleton.Instance; // Part 2: write ending message. instance.Message(); } } public sealed class Singleton { static readonly Singleton _instance = new Singleton(); public static Singleton Instance { get { return _instance; } } public void Message() { Console.WriteLine("DONE"); } Singleton() { // Perform initialization steps. } }
Benchmark, static methods. Static methods have a performance advantage. They are normally faster to invoke on the call stack than instance methods.
Important Instance methods have the "this" instance pointer as the first parameter. And they use callvirt for calls.
Version 1 This code calls a static method. Note that we use MethodImplOptions.NoInlining to keep the compiler from inlining here.
Version 2 This version is an instance method with the same MethodImpl attribute. It requires a Program class instance.
Result It is faster to invoke a static method—the instance "this" and the callvirt instruction are not needed.
using System; using System.Diagnostics; using System.Runtime.CompilerServices; class Program { [MethodImpl(MethodImplOptions.NoInlining)] static double GetNumber() { return 3; } [MethodImpl(MethodImplOptions.NoInlining)] double GetNumber2() { return 3; } const int _max = 1000000000; static void Main() { Program program = new Program(); // Version 1: use static method call. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (GetNumber() == -1) { return; } } s1.Stop(); // Version 2: use instance method call. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { if (program.GetNumber2() == -1) { return; } } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } }
1.94 ns static GetNumber 2.46 ns GetNumber2 (instance method)
Benchmark, static constructor. Let us consider 2 classes to test how static constructors influence performance in C#. We see HasStaticConstructor and NoStaticConstructor.
Version 1 This class (creatively named HasStaticConstructor) has a static constructor: it initializes its field to 1.
Version 2 The second class has no static constructor. This version of the code just initializes the field inline.
Result Static constructors cause a slowdown of all accesses to the type. This is small in absolute terms, but can add up in a program.
Info There is some complexity here, but it is best to avoid static constructors for performance.
using System; using System.Diagnostics; static class HasStaticConstructor { public static int _test; static HasStaticConstructor() { _test = 1; } } static class NoStaticConstructor { public static int _test = 1; } class Program { const int _max = 1000000; static void Main() { var s1 = Stopwatch.StartNew(); // Version 1: assign field in class that has static constructor. for (int i = 0; i < _max; i++) { HasStaticConstructor._test = 2; } s1.Stop(); var s2 = Stopwatch.StartNew(); // Version 2: assign field in class that does not have a static constructor. for (int i = 0; i < _max; i++) { NoStaticConstructor._test = 2; } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000000) / _max).ToString("0.00 ns")); } }
2.16 ns Has static constructor 0.55 ns No static constructor
Benchmark, static fields. When we access an instance field, the "instance reference" must be resolved. This is a layer of indirection.
Detail For static fields, there is no instance to resolve, so some performance benefit may be observed.
Version 1 This code increments several instance int fields in a method. We compare its time to a version that uses static.
Version 2 This code instead increments static int fields. It performs slightly faster. This will not be noticeable in many programs.
Result It is faster to access, and mutate, the value in a static field than one in an instance field.
using System; using System.Diagnostics; class Test1 { int _a; int _b; int _c; public void X() { // Change instance field values. this._a++; this._b++; this._c++; } } class Test2 { static int _a; static int _b; static int _c; public void X() { // Change static field values. _a++; _b++; _c++; } } class Program { const int _max = 200000000; static void Main() { Test1 test1 = new Test1(); Test2 test2 = new Test2(); // Version 1: use instance fields. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { test1.X(); test1.X(); test1.X(); test1.X(); test1.X(); } s1.Stop(); // Version 2: use static fields. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { test2.X(); test2.X(); test2.X(); test2.X(); test2.X(); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00") + " ns"); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00") + " ns"); } }
7.71 ns Instance field increment 7.44 ns Static field increment
Benchmark, locals. Static fields may be faster to access than instance fields. But if we copy them into a local variable, this is faster still.
Version 1 This code accesses a static int field and increments it 10 times. The field is modified 10 times.
Version 2 This version copies the value of the static field into a local variable, increments that, and stores the result at the end.
Result For a speedup, try caching a field in a local variable while it is being used, and then storing it at the end.
using System; using System.Diagnostics; class Program { static int _temp1; // Static field static void Method1() { // Increment the static field ten times. for (int i = 0; i < 10; i++) { _temp1++; } } static void Method2() { // Load static field into variable. // ... Increment that ten times, then copy the value. int copy = _temp1; for (int i = 0; i < 10; i++) { copy++; } _temp1 = copy; } const int _max = 1000000; static void Main() { // Version 1: increment static field. var s1 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { Method1(); } s1.Stop(); // Version 2: increment local variable field. var s2 = Stopwatch.StartNew(); for (int i = 0; i < _max; i++) { Method2(); } s2.Stop(); Console.WriteLine(((double)(s1.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00 ns")); Console.WriteLine(((double)(s2.Elapsed.TotalMilliseconds * 1000 * 1000) / _max).ToString("0.00 ns")); } }
14.83 ns Increment static 3.59 ns Increment local
Summary. Static methods (and classes) access type-based data, like global variables and single-instance fields. To reduce invalid data problems, avoid statics and create a class instance.
Dot Net Perls is a collection of tested code examples. Pages are continually updated to stay current, with code correctness a top priority.
Sam Allen is passionate about computer languages. In the past, his work has been recommended by Apple and Microsoft and he has studied computers at a selective university in the United States.
This page was last updated on Apr 16, 2024 (simplify).
© 2007-2024 Sam Allen.