I’ve been known to say, “Static classes are evil.” That’s overstating my position somewhat, but a static class will definitely raise a red flag in a code review. The plain truth is that in a language like C# there’s seldom a need for a static class, and there are compelling reasons not to use them. They have their uses, but in my experience you should favor class instances over static classes whenever reasonable.
In C#, static class constructors run immediately before the first static method on its class is called, or (in the case of an instance class that has static members) immediately before the first instance of its class is created. Eric Lippert explains this in detail in his article series about static constructors.
It’s important to understand that, in general, you have no control over when the constructor runs. In addition, you can’t pass parameters to the static constructor. The constructor must have all the information it needs in order to fully initialize the class and all of its members. If the constructor can’t fully initialize things, then what you have is equivalent to a partially initialized object at global scope.
Let me illustrate why this is a bad thing.
First, suppose you have this (non-static) class:
public class Foo
{
public Foo() {} // parameterless constructor
public void Initialize(string bar); // sets up the object
// DoSomeWork does something that depends on Initialize being called.
public void DoSomeWork();
}
And you use it in code like this:
private void SomeMethod()
{
var f = new Foo();
Foo.Initialize("xyzzy");
Foo.DoSomeWork();
}
The key here is that if you don’t call Initialize
first, then DoSomething
is going to fail. This API is somewhat fragile because nothing stops the programmer from forgetting to initialize. In almost all cases, it would be better to have the constructor initialize the object:
public class Foo
{
public Foo(string bar) {} // create and initialize the object
public void DoSomeWork();
}
Now, it’s impossible to create an uninitialized object, meaning that it’s always safe to call DoSomeWork
.
As bad as this API is, it’s not too bad because you control the scope of the uninitialized object. It’s not like code in some other method can reach in and access your Foo
instance.
Now imagine you create a static class with a similar interface:
public static class Foo
{
static Foo() {} // static class constructor
public static void Initialize(string bar); // sets up the object
// DoSomeWork does something that depends on Initialize being called.
public static void DoSomeWork();
}
Remember, the static class is at global scope. Any part of your program can reference the namespace and call methods on this class. They don’t have to construct it. It’s all too easy to write somewhere in your program:
Foo.DoSomeWork();
If that’s the first reference to Foo
in your program, the constructor will run, Initialize
won’t be called, and your static class will either crash and burn or, probably worse, do something with the default values. You better hope that your defaults aren’t dangerous.
If your static class requires any explicit initialization on your part (i.e. you have to call an Initialize
method), then you probably should revisit your design. It’s almost a certainty that you should re-code that to be an instance class with a constructor that accepts a parameter and creates a fully initialized object. I think you’ll discover that your code is cleaner without the static classes.