Static classes in C# are an important tool that most developers should
know how to use effectively. The confusion usually surfaces when dealing
with static constructors to set up a static class. Static constructors
can be used to initialize classes, utilities, and even singletons. Understanding
some of the issues surrounding static constructors, like beforeFieldInit
and static field initialization, will help you effectively use static
initialization features of your static class.
public class UtilityClass
{
//
// Resources
//
// r1 will be initialized by the static constructor
static Resource1 r1 = null;
// r2 will be initialized first as static constructors are
// invoked after the static variables are initialized
static Resource2 r2 = new Resource2();
//Notice how there is no public modifier
//Access modifiers are not allowed on static constructors
static UtilityClass()
{
r1 = new Resource1();
}
static void f1(){}
static void f2(){}
}
Resource initialization is a common occurrence in programming. I have seen many libraries in different languages where a developer has to explicitly initialize a facility before starting to use the library. In most object-oriented languages, this problem is tackled using static variables and constructors that get called in response to the instantiation of those static variables.
C#, while retaining this ability to use static variables for initialization, also provides a language construct called the "static constructor." Static constructors provide a clean way to solve the initialization problems in C# programs.
Let me explore an initialization example to illustrate the various aspects of static constructors. Imagine a case where you are writing a utility class with a set of public static functions. The intention is that other programmers can use these static functions in their programs without explicitly instantiating the class.
public class UtilityClass
{
public static void f1(){}
public static void f2(){}
}
If these functions require some resources that need to be acquired at
the start and kept for the life of the program, then there needs to
be a way to initialize these resources. To demonstrate this case let
me add a resource variable called r1 of type Resource1 to this UtilityClass.
Let us initially set the resource to null while we decide on a good way
to initialize it. At this stage, the modified class will look like this:
public class UtilityClass
{
//Resources
static Resource1 r1 = null;
static void f1(){}
static void f2(){}
}
One of the ways to initialize this resource to other than null is to
directly instantiate the Resource1 inline. The following code demonstrates
the common practice of newing classes for static variables inline wherever
the static variables are defined.
public class UtilityClass
{
//Resources
static Resource1 r1 = new Resource1();
static void f1(){}
static void f2(){}
}
|
Related Reading
Programming C# |
This is called static field initialization, where field r1 of type
Resource1 is initialized. We are encouraged to do this because, intuitively,
we argued with ourselves that this initialization will happen before
any of the other static functions are called. So if f1() or f2() is
to be called, there is an assumption that r1 should have been initialized
by then. But read on to find otherwise.
beforeFieldInit: The Fly in the Ointment There is an exception to this perfect rule. If this class is marked
as beforeFieldInit, then r1 may not be initialized when the functions
are called. According to the CLI, "beforeFieldInit specifies that
calling static methods of the type does not force the system to initialize
the type." This means that the static variables are not initialized
just because we called a static function. But CLI does insist that all of
the field variables will be initialized as soon as one of the static
fields is accessed. So if we are depending on some side effects based
on static variable initialization, then we may be waiting for a long
time that to happen.
beforeFieldInit Why did CLI do this? The CLI specification claims that it is expensive
to ensure that type initializers are run before a static method is called,
particularly when executed from multiple application domains. CLI feels
that this is OK most of the time. Let me examine this claim in some
detail. In the code example above, say that f1() uses r1, and f2() does not
use r1. If f2() is called, it doesn't reference r1 and hence, r1 is not
initialized. As long as f2() doesn't depend on the initialization of
r1 indirectly, this is OK. But what if in the process of instantiating
r1, the constructor of Resource1() sets up a static hash table in some
other class upon which f2() depends? As long as these side effects are
not going on, then the facility of beforeFieldInit is fine.
In other words, if you need a system- or module-wide initialization, then use a different approach and don't depend on the side effects produced by static variable initialization. So initialization of a class should be a separate language construct, rather than being a side effect of field initialization. "Static constructor" is one such language construct with initialization semantics.
Before covering the static constructors it is worth noting that the CLI specification goes on to warn us about assumptions about base class type initialization. It tells us that don't expect any such initialization to happen automatically. To quote CLI: "Execution of any type's initializer method will not trigger automatic execution of any initializer methods defined by its base type, nor of any interfaces that the type implements."
Let us modify the above class and initialize r1 through a static constructor
instead. The resulting class will look like the following:
public class UtilityClass
{
//Resources
static Resource1 r1 = null;
static UtilityClass()
{
r1 = new Resource1();
}
static void f1(){}
static void f2(){}
}
There is an assurance in the language that this static constructor gets called before any other static method gets called. That means that it is guaranteed that the variables will be initialized before any static function is invoked on that class. Let us look at what the C# documentation says about static constructors:
To further understand and elaborate on the above rules, let us consider the following class definition:
public class UtilityClass
{
//Resources
static Resource1 r1 = null;
static Resource2 r2 = new Resource2();
static UtilityClass()
{
r1 = new Resource1();
}
static void f1(){}
static void f2(){}
}
|
beforeFieldInit Interestingly enough, according to the rules resource, r2 gets initialized
first, before the static constructor is called and r1 is initialized.
Even if r2 is never needed, it will still be initialized first. Defining
a static constructor seems to "trump" the beforeFieldInit. So even
if you have an empty static constructor, it is guaranteed that static
variables will be initialized before any static function gets invoked.
If there is no static constructor, then the following rule taken from the C# documentation applies to the initialization of static variables:
"The static field variable initializers of a class correspond to a sequence of assignments that are executed at an implementation-dependent time prior to the static constructor for the class (if any) and prior to the first use of a static field of that class. The static field variable initializers are executed in the textual order in which they appear in the class declaration."
static
in front.beforeFieldInit. If all of your static variables can be set up by simply instantiating classes
against them, then there is a good chance that you don't need a static
constructor. What you have to watch out for, though, is that none of the constructors
of these classes have side effects; for example, a class1 constructor doing
something useful for a class2 constructor, or the usage of a class2 instance.
In such a case, if a class2 variable is to be utilized first, then
there is no guarantee that a class1 constructor would have run. Surprisingly,
even this won't be a problem if these instances are the static instances
of the same class; as soon as one of the class instances is
utilized, everything in that class is initialized.
If a class has a set of static variables that are mainly simple types
and not functional classes, then these simple types need to be initialized
procedurally, as opposed to instantiating them. For example, I consider ints, strings,
etc., as simple types (although they are classes in their
own right). A logging class needs to remember its log filename,
log message levels etc., at start up. Assuming this log class is implemented
as a static class, a static constructor will initialize these variables.
If you want to do this using static variable initialization, then you
need to have a class called LogInitialization, whose sole purpose is
to initialize this static instance.
public class MySingletonClass
{
public static MySingletonClass self = new MySingletonClass();
//Nonstatic MySIngletonClass implementation follow
}
//singletonusage
MySingletonClass.self.doSomething();
The above example shows that the majority of singletons don't require static
initializers.
There is no such language construct called a static class. I tend to refer to a class as a static class when much of its functionality is exposed as a collection of static functions. Often, these classes give rise to static constructors. It is possible to convert a static class to a regular class and use a singleton of this type, instead of the static class with which we have started. There are pros and cons to both approaches. First, let me show examples of both usages.
//Class definition
public class UtilityClass
{
//Resources
static Resource1 r1 = null;
static void f1(){}
static void f2(){}
}
//Let us see how the above class is used
UtilityClass.f1();
UtilityClass.f2();
In this scenario, programmers will directly call the static functions as if they are C-like functions. This approach has a lot of simplicity and as a result, is usually preferred for utility functions. On the negative side of this approach lies the first assertion that this is not object-oriented programming. If it gets the job done, and programmers use it without major drawbacks, this is quite reasonable.
Let me rewrite the above class as a singleton and show how programmers can use such a facility.
//Class definition
public class SingletonUtilityClass
{
public static SingletonUtilityClass self = new SingletonUtilityClass();
//Resources
Resource1 r1 = null;
void f1(){}
void f2(){}
}
//Let us see how the above class is used
SingletonUtilityClass.self.f1();
SingletonUtilityClass.self.f2();
Notice now that the class is a non-static, regular class. The only static variable is the "self" variable pointing to an instance of itself. This is a little bit more verbose than the static version of it. In addition to that you have to ensure the singleton semantics of it. You should ensure that the constructor of this is private and is not allowed to instantiate from anywhere, etc.
There is a reward for going this extra step. In the above example, the class is statically bound to the program. If you can utilize a factory that can dynamically instantiate classes and also permits the multiplicity of their instantiations, then you can take the above class and makes it a strategy/factory pattern. Once this happens, you can then change your implementation of methods at run time. When properly expanded, this method forms the basis of remoting, COM+, etc.
Satya Komatineni is the CTO at Indent, Inc. and the author of Aspire, an open source web development RAD tool for J2EE/XML.
Return to ONDotnet.com
Copyright © 2009 O'Reilly Media, Inc.