We all use the static keyword, but do we really know what the
possibilities are?
Prologue
The static keyword is, in general, an
instance-less "thing". By "thing", I mean that it can be a variable,
a class, a property and more... This definition has different meanings according
to which "thing" it's related to.
Let's look into it...
Static Variables
A static variable is the most common use of the static
keyword I guess (I don't think there has been a real research to confirm
that!).
Marking a variable as static means that:
- This variable value will be kept through different instances of the class because only one copy of it exists.
- It cannot be accessed through an instance of a class nor using the this keyword.
- It will be initialized as soon as its class is initialized or as soon as a method that uses it is called.
- It will be disposed when the application domain is shutting down.
Demo:
public class MyClassWithAStaticVar
{
public static int x;
public void Go()
{
// this.x = 5; <-- Impossible!
x = 6; // good!
MyClassWithAStaticVar.x = 6; // good!
}
}
public class Demo
{
public void DoSomething()
{
MyClassWithAStaticVar a = new MyClassWithAStaticVar();
MyClassWithAStaticVar b = new MyClassWithAStaticVar();
// a.x = 6; <-- Impossible!
MyClassWithAStaticVar.x = 6;
// Now both MyClassWithAStaticVar instances (a and b)
// will get 6 when they ask for x value.
}
}
Static Events
Very similar to static variables, static events are not associated with a specific instance of the class. All rules of static variables apply here as well.
Demo:
public class StaticEvents
{
public static event EventHandler MyStaticEvent;
public void DoSomething()
{
// this.MyStaticEvent(this, EventArgs.Empty); // <-- Impossible!
MyStaticEvent(this, EventArgs.Empty); // good!
}
}
public class StaticEventsTester
{
public void DoSomething()
{
StaticEvents s = new StaticEvents();
// s.MyStaticEvent += StaticEvents_MyStaticEvent; // <-- Impossible!
StaticEvents.MyStaticEvent += StaticEvents_MyStaticEvent; // good!
}
void StaticEvents_MyStaticEvent(object sender, EventArgs e)
{
// ...
}
}
Static Properties/Methods
Defining a property or a method as static can be useful when their logic is not affected by the object state.
Setting a property/method as static means that:
- It can only access other static objects.
- It cannot be accessed through an instance of the class nor using the this keyword.
Demo:
public class StaticPropsAndMethods
{
private bool dayOff;
public static bool IsItMonday
{
get
{
return (DateTime.Now.DayOfWeek == DayOfWeek.Monday);
}
set
{
throw new YouAreNotGodException("Monday will come if you want it or not!");
}
}
public static void TakeTheDayOff()
{
if (IsItMonday)
{
// dayOff = true; // <-- Impossible! dayOff is not static...
// Now you will have to work on Monday!
}
}
}
Static Constructors
Static constructors, as instance constructors, should initialize its class related members. They do have some significant differences though:
- A static constructor is called between 0 to 1 times during the application domain lifetime.
- It is triggered when the class is created for the first time or as soon as one of the class' static members is called.
- It cannot have parameters.
- It cannot have access modifiers (private, public...)
- It can access only static members of the class.
- It cannot be called directly.
These points make static constructors a unique and very important place for various operations - find out when your class is called at the first time,
validate class related requirements, execute one-time-only actions, etc.
Demo:
public class MyStaticConstructor
{
// public static MyStaticConstructor(int i) { } // <-- Impossible!
static MyStaticConstructor() // good!
{
// Do some static related
// operations and initializations
}
}
Static Classes
Declaring a class as static doesn't give it special abilities, but it is very important for keeping the right design and purpose to the specific class.
Declaring a class as static means that:
- All of the class members must be declared as static as well (including constructors).
- An instance of the class cannot be created.
- The class is sealed, so it cannot be inherited.
- The class cannot inherit from a base class or an interface.
Going through this list, one can assume that a static class is much the same like a regular class that
has static members only. This is almost correct - when a class is set as
static, the compiler makes sure that no instances of the class are being created.
Setting a class as
static can be very helpful for helper classes. It will help to permanence the
class as a helper class with helper methods.
Demo:
public static class MyStaticClass
{
//public void MyMethod()
//{ // <--
// // <-- Impossible!
//} // <--
public static void MyMethod() { } // good!
}
// public static class ChildStaticClass : MyStaticClass {} // <-- impossible!
public class Demo
{
public void DoSomething()
{
// MyStaticClass c = new MyStaticClass(); <-- Impossible!
MyStaticClass.MyMethod(); // good!
}
}
Where static Cannot Be Applied
There are a couple of places where the static keyboard cannot be declared: const and type declarations. This is because these
are already static. This means that all of the rules that apply to static variables apply to constant and types within a class.
Demo:
public class NoStatic
{
// public static const int StaticInt = 1; // <-- Impossible!
public const int StaticInt = 1; // good!
//public static enum ABC // <-- Impossible!
public enum ABC // good!
{
A,
B,
C
}
public void Test()
{
// int j = this.StaticInt; // <-- Impossible!
}
}
public class AnotherClass
{
public void DoSomething()
{
NoStatic s = new NoStatic();
// int j = s.StaticInt; // <-- Impossible!
int j = NoStatic.StaticInt; // good!
//int k = (int)s.ABC.C; // <-- Impossible!
int k = (int)NoStatic.ABC.C; // good!
}
}
[ThreadStatic]
This is something that is not commonly used and might be helpful sometimes. Use this attribute above static variables in order to make them
thread specific.
This means that the variable behaves as static for each thread and not for the whole application.
Notice that using this attribute makes the variable thread-safe.
Epilogue
As I've tried to pass in this post, static is a very powerful keyword BUT it should be used wisely.
One thing to remember - there are no static destructors in .Net. This means that you'll find it hard to release static resources (there are ways, but they
are workarounds and workarounds are evil!).
Demo - how NOTto use static classes:
public static class AbusedStaticClass
{
// Please do NOT code like that! Pleaseeeeeeee!
public static StreamWriter MyFile;
static AbusedStaticClass()
{
MyFile = new StreamWriter(@"DontDoThis.txt");
}
}
This was a long post! Kudos to those who made it to the end! :)
I hope you've been enlightened,
All the best,
Shay.