HomeSearch

C# Static Method, Class and Constructor

Use the static keyword. Create static methods, static classes and static constructors.

Static.

In the distance there is a mountain. It does not appear to move—it is static. Static things are singular. A static class is only present in one place in a program.

Static methods

can be placed upon a static type. So too can static fields. Upon the static mountain we can construct many things (but not that same mountain twice).

First example.

Classes are created as instances. But static fields are part of no instance. Static things exist in a separate, singular place (like the mountain).

Intro: This program shows a static class, field and method. It shows the syntax. Main() is a special case of a static method.

Field: In this program, we see that the static field is displayed, then set to int.MaxValue, and finally displayed again.

Class: In a static class, all fields and methods must also be static. This is a useful restriction—it helps keep code maintainable.

Class
C# program that uses static keyword using System; static class Mountain { public static int _value = 5; } class Program { static void Main() { // Print the value of the Mountain field. Console.WriteLine("STATIC FIELD: " + Mountain._value); // Change the value, then print it again. Mountain._value = int.MaxValue; Console.WriteLine("STATIC FIELD: " + Mountain._value); } } Output STATIC FIELD: 5 STATIC FIELD: 2147483647

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.

Instance: An instance method can access those members, but must be called through an instantiated object. This adds indirection.

C# program that uses instance and static methods 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()); } } Output 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.Property

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.

C# program that uses static properties 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); } } Output 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.

C# program that uses static field 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); } } Output 1

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.

Program: To start, there are 2 classes in this program: the Program class, which is not static, and the Perl class, which is static.

And: You 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.

C# program that demonstrates 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"); } } Output Blended

Notes, static class.

Conceptually, a static class is a form of information hiding. The static modifier imposes an extra restriction. The constructor is eliminated.

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.

Constructor
C# program that uses static constructor 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); } } Output 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.

Abs: We can invoke Math.Abs with just the "Abs" function name. The static System.Math provides this.

WriteLine: We avoid specifying Console in the WriteLine call. The "using static System.Console" directive is needed.

C# program that shows using static syntax 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); } } Output 100

Performance, static methods.

Static methods have a performance advantage. They are normally faster to invoke on the call stack than instance methods.

Important: Instance methods actually use the "this" instance pointer as the first parameter. They will always have that overhead.

Callvirt: Instance methods are also implemented with the callvirt instruction, which imposes a slight overhead.

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.

C# program that tests static method performance 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")); } } Output 1.94 ns static GetNumber 2.46 ns GetNumber2 (instance method)

Performance, 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.

C# program that benchmarks static constructors 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")); } } Output 2.16 ns Has static constructor 0.55 ns No static constructor

Benchmark, continued.

Static constructors are sometimes not slower. It is possible to have code that accesses a field in a class with a static constructor, with no performance penalty.

And: This seems to depend on how early in the program the field is first accessed.

Thus: It is best to avoid static constructors for maximum performance. Bogdan Potor wrote in with a benchmark.

Performance, static fields.

When we access an instance field, the "instance reference" must be resolved. This is a layer of indirection.

Meanwhile: 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.

C# program that benchmarks static fields 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"); } } Output 7.71 ns Instance field increment 7.44 ns Static field increment

Performance, 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.

Tip: For a speedup, try caching a field in a local variable while it is being used, and then storing it at the end.

C# program that benchmarks fields and locals 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")); } } Output 14.83 ns Increment static 3.59 ns Increment local

Static types.

We can make many members and types static. This is often a useful technique for sharing the member among many uses. We consider arrays, Regex and strings.Static ArrayStatic DictionaryStatic RegexStatic String

Readonly: The C# specification recommends using "public static readonly" variables for constants that must initialized at runtime.

Readonly

Const.

This specifies that a variable will never change. When we use const, we cannot reassign the variable. It is substituted directly as needed by the compiler.const

Singleton.

This design pattern gives us an object that can only be instantiated once. The implementation uses a private constructor. Singletons are object instances, unlike static classes.SingletonSingleton vs. Static

Public, private.

Utility (helper) classes often contain public static methods. This results in no performance loss. These methods are available throughout a program.Public, privateProtected, internal

Instructions.

We understand static fields if we look at the IL instructions. This also gives us a good idea of how static modifiers affect performance. Often "static" enhances performance.IL: stsfld, ldsfld and ldc

Research.

The concept of "statics" is core to many languages. In C# we cannot use static to describe local variables. Static modifies a field's storage location.

Quote: A static field identifies exactly one storage location to be shared by all instances of a given closed class type (The C# Programming Language).

Access routines: The book Code Complete (by Steve McConnell) shows strategies to employ global variables in programs.

Global Variable

Research, locals.

Static locals are a storage-permanent local variable in the C and C++ languages. This concept does not exist in C#. But const can be used in a method.

A review.

We use static methods to access type-based data. With static classes, we handle global variables and single-instance fields. Static constructors initialize data, but may be slow.

A note.

Statics introduce complications. It is possible for the values of static fields to become invalid. In these situations, class instances are a better approach.
Home
Dot Net Perls
© 2007-2019 Sam Allen. All rights reserved. Written by Sam Allen, info@dotnetperls.com.