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.
Classes are created as instances. But static
fields are part of no instance. Static things exist in a separate, singular place.
static
class
, all fields and methods must also be static
. This is a useful restriction—it helps keep code maintainable.static
field is displayed. In the static
class
, the field has been initialized to 5.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 FIELD: 5 STATIC FIELD: 2147483647
These are called with the type name. No instance is required—this makes them slightly faster. Static methods can be public or private.
static
keyword, usually as the first keyword or the second keyword after public.static
method cannot access non-static
class
level members. It has no "this" pointer.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
These are similar to static
methods. In the metadata, properties have the word "get_" or "set_" prefixed to their identifiers.
static
properties in the same way as static
methods. Properties show the same performance levels of methods.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 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.
static
field does not have to be a value type. It can instead be a reference.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); } }1
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
.
static
class
cannot have non-static
members. All methods, fields and properties in it must also be static
.Program
class
, which is not static
, and the Perl class
, which is static
.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"); } }Blended
A static
constructor initializes static
fields. It runs at an indeterminate time before those fields are used. Static constructors impose some overhead.
static
constructor is sometimes called a type initializer. It initializes fields before accesses.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
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.
Math.Abs
with just the "Abs
" function name. The static
System.Math
provides this.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); } }100
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.
readonly
and static
keywords are used. Readonly allows thread-safety, and that means it can be only allocated once.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. } }DONE
static
methodsStatic methods have a performance advantage. They are normally faster to invoke on the call stack than instance methods.
callvirt
for calls.static
method. Note that we use MethodImplOptions.NoInlining
to keep the compiler from inlining here.MethodImpl
attribute. It requires a Program
class
instance.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)
static
constructorLet us consider 2 classes to test how static
constructors influence performance in C#. We see HasStaticConstructor
and NoStaticConstructor
.
class
(creatively named HasStaticConstructor
) has a static
constructor: it initializes its field to 1.class
has no static
constructor. This version of the code just initializes the field inline.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
static
fieldsWhen we access an instance field, the "instance reference" must be resolved. This is a layer of indirection.
static
fields, there is no instance to resolve, so some performance benefit may be observed.int
fields in a method. We compare its time to a version that uses static
.static
int
fields. It performs slightly faster. This will not be noticeable in many programs.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
Static fields may be faster to access than instance fields. But if we copy them into a local variable, this is faster still.
static
int
field and increments it 10 times. The field is modified 10 times.static
field into a local variable, increments that, and stores the result 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
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.