C-Sharp | Java | Python | Swift | GO | WPF | Ruby | Scala | F# | JavaScript | SQL | PHP | Angular | HTML
Info: In a static class, all fields and methods must also be static. This is a useful restriction—it helps keep code maintainable.
ClassStep 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.
C# program that uses static keyword
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);
}
}
Output
STATIC FIELD: 5
STATIC FIELD: 2147483647
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
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
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
Note: A static class cannot have non-static members. All methods, fields and properties in it must also be static.
Program: 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.
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
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.
ConstructorC# 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
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
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.
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)
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. Bogdan Potor wrote in with a benchmark.
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
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.
Result: It is faster to access, and mutate, the value in a static field than one in an instance field.
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
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.
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
Readonly: The C# specification recommends using "public static readonly" variables for constants that must initialized at runtime.
ReadonlyQuote: 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