Thursday, January 17, 2008

 

Static Classes, Abstract Classes and the Singleton Pattern

The .NET framework 2.0 introduced the concept of static classes. A static class is marked with the keyword static, cannot be instantiated and can only have static members. It can have static fields, properties, methods, events, indexers and even a parameterless static constructor (refer to a previous post on static constructors.)

You cannot derive one static class from another class (static or non-static); static classes are always sealed! This is because the object-oriented paradigms such as inheritance and polymorphism make absolutely no sense without runtime instances of objects. Likewise, you cannot cast an instance of any object to a static class because that makes no sense.

Like a static class, an abstract class cannot be instantiated. And, like a static class, an abstract class can contain static fields, properties, methods, events, indexers and static constructors. But, the intended purpose of a static class is very different from that of an abstract class. Unlike a static class from which you cannot derive other classes, the whole purpose of an abstract class is to act as a base class from which you will derive other classes. In addition to its static members, an abstract class can also have instance fields, properties, methods, events, indexers and constructors. And, although an abstract class cannot be created with new, an instance of a class derived from an abstract class can be cast to the abstract class using as.

A class that is declared with neither the static nor abstract keyword can also contain static fields, properties, methods, events, indexers and constructors. And, such a class can also have instance fields, properties, methods, events, indexers and constructors. But, unlike static and abstract classes, a class that is neither static nor abstract can be instantiated with new and can be cast as any class "above it" in the class derivation tree.

Before static classes, one of the old "tricks" was to define a private constructor. By default, if a class defines no instance consructors the compiler will automatically create a parameterless default constructor. But, if even a single instance constructor is defined with any number of parameters and any access level, the compiler will not create the default constructor.

If all three types of classes can contain static fields, properties, methods, events indexers and constructors, you may wonder why a static class is needed at all. Especially if you can define a private constructor to keep an object from being created. The answer is simple: the sooner you find a bug, the cheaper it is to fix. One of the common bugs of many [even experienced] developers is to accidentally leave the static keyword off of members that are intended to be static. Defining the class as static enforces the intended design by providing compile-time errors if non-static members are encountered.

So-called "Function library" classes are an excellent use for static classes, especially since C#.NET does not support functions defined outside of a class. This is particularly useful if such functions work on interfaces instead of objects instances, thus allowing you to pass-in objects from any derivation tree as long as they support the interface. In such classes, each method is typically is a self-contained function.

You can even use a static class to implement something like a singleton pattern, as is shown in the example below compared to a more typical singleton pattern.


// Define the static singleton class
static class StaticSingleton
{
// It is adviseable to make to lock object readonly
// to prevent it from being changed accidentally
private static readonly object s_dataLock =
new object();

private static long s_count = 0;

public static long Increment()
{
long newValue;
lock(s_dataLock )
{
newValue = ++s_count;
}
return newValue;
}

public static long Decrement()
{
long newValue;
lock(s_dataLock )
{
newValue = --s_count;
}
return newValue;
}
}


// Define the instance singleton class
// It is adviseable to make all singleton classes sealed.
class sealed InstanceSingleton
{
// It is adviseable to make to the singleton object
// readonly to prevent it from being changed accidentally
private static readonly InstanceSingle s_instance =
new InstanceSingleton();

// It is adviseable to make to lock object readonly
// to prevent it from being changed accidentally
private readonly object _flagLock = new object();

private long _count = 0;

// Constructor is private to ensure that an instance can
// only be created by the class
private InstanceSingleton()
{
}

// Returns a reference to the instance
public static Instance
{
get
{
return s_instance;
}
}

public long Increment()
{
long newValue;
lock(_dataLock )
{
newValue = ++_count;
}
return newValue;
}

public long Decrement()
{
long newValue;
lock(_dataLock )
{
newValue = --_count;
}
return newValue;
}
}

// Using the static singleton
StaticSingleton.Increment();
StaticSingleton.Decrement();

// Using the instance singleton
InstanceSingleton.Instance.Increment();
InstanceSingleton.Instance.Decrement();
 

Although not technically a singleton because it never creates an instance of an object, the static class approach takes less code to implement and use. However, using a static class as a singleton does not give me a "warm and cozy feeling". I am not a big fan of it for several reasons, all of which arise because there is not instance of an object.



This blog post was not really intended to be a "best practices" on implementing a singleton pattern in C#. Rather, it was simply intended to highlight a few things about static classes. If you're interested in learning more about instance singleton patterns in C#, checkout the Microsoft Patterns & Practices: Implementing Singleton in C#

Comments: Post a Comment





<< Home

This page is powered by Blogger. Isn't yours?

Subscribe to Posts [Atom]