Implementing a Singleton Pattern in C#
page 1 of 1
Published: 24 Apr 2006
Unedited - Community Contributed
Abstract
A singleton pattern is one that states that there would be only one instance of a class throughout the application domain. This article illustrates this pattern with lucid code examples.
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 11809/ 16

A Singleton class is one that allows only one instance of it to be created in the lifetime of an application. This article discusses the singleton pattern, one of the most well known patterns in software engineering with lucid examples.

What is a Singleton Class?

A singleton class is one that can be instantiated only once in the application domain and provides a global point of access to it. In this article we would implement a StateManager class that manages the storage and/or retrieval of objects in the Cache, Application and Session. We require only one instance of this class to be created throughout the application’s lifetime.

Implementing the Singleton Pattern

We declare an enum called State that holds the following values:

·         Application

·         Session

·         Cache

·         ViewState

The enum is as given below:

Listing I: The State enum

 
public enum State
      {
            Application,Session,Cache,ViewState
      }

The StateManager class shown below manages the storage and/or retrieval of objects to the states mentioned above. The class is sealed to help JIT in optimization and contains a private constructor to prevent instantiation directly.

Listing II: The StateManager class

 

public sealed class StateManager
      {
            private static StateManager obj =null;
            private System.Web.UI.StateBagViewState = new StateBag();
                        
            private StateManager()
            {
              
            }
 
            public static StateManager Instance
            {
                  get
                  {
                        if(obj == null)
                              obj = newStateManager();
                        return obj;
                  }
            }
 
            public void Add(string key,objectdata,State state)
            {
                  switch(state)
                  {
                        case State.Application: 
                        HttpContext.Current.Application.Add(key,data);
                              break;
                        case State.Session: 
                        HttpContext.Current.Session.Add(key,data);
                              break;
                        case State.Cache: 
                        HttpContext.Current.Cache.Insert(key,data);
                              break;
                        case State.ViewState:ViewState.Add(key,data);
                              break;
                  }
            }
 
            public void Remove(string key,Statestate)
            {
                  switch(state)
                  {
                        case State.Application: 
                              if(HttpContext.Current.Application[key] 
                                    != null)                      
                              HttpContext.Current.Application.
                              Remove(key); 
                              break;
                        case State.Session: 
                              if(HttpContext.Current.Session[key] != 
                              null)
                              HttpContext.Current.Session.Remove(key);
                              break;
                        case State.Cache: 
                              if(HttpContext.Current.Cache[key] != 
                                    null)                         
                              HttpContext.Current.Cache.Remove(key);
                              break;
                        case State.ViewState: 
                              if(ViewState [key]!= null)
                              ViewState.Remove(key);
                              break;
                  }
            }
 
            public object Get(string key,Statestate)
            {
                  switch(state)
                  {
                        case State.Application: 
                              if(HttpContext.Current.Application[key] 
                                    != null)
                              returnHttpContext.Current.
                              Application[key];
                              break;
                        case State.Session:
                              if(HttpContext.Current.Session[key] != 
                              null)
                              returnHttpContext.Current.Session[key];
                              break;
                        case State.Cache: 
                              if(HttpContext.Current.Cache[key] != 
                              null)
                              returnHttpContext.Current.Cache[key];
                              break;
                        case State.ViewState: 
                              if(ViewState[key]!= null)
                              returnViewState[key];
                              break;
                        defaultreturn null;
                  }
                  return null;
            }
 
            public int Count(State state)
            {
                  switch(state)
                  {
                        case State.Application: 
                        if(HttpContext.Current.Application!= 
                        null)
                        returnHttpContext.Current.Application.
                        Count;
                        break;
                        case State.Session: 
                        if(HttpContext.Current.Session!= null)
                        returnHttpContext.Current.Session.Count;
                        break;
                        case State.Cache: 
                        if(HttpContext.Current.Cache!= null)
                        returnHttpContext.Current.Cache.Count;
                        break;
                        case State.ViewState:
                        if(ViewState != null)
                        return ViewState.Count;
                        break;
                        default: 
                        return 0;
                  }
                  return 0;
            }
      }

The method Add stores objects in the respective states based value on the object of the State enum as parameter. The Remove method removes the objects and the Count method is responsible for returning the number of objects stored in these states. This implementation is not thread safe, however. There can be two threads trying to access the property instance at the same point of time. If both of these threads evaluated the condition if(obj == null) and found it true, then both would have created the objects which would violate the pattern. Hence, we should have some way of providing thread safety to the creation of the object of this class. The following code is a thread safe version of the same class.

Listing III: The thread safe and lazy State Manager  class.

 
using System;
using System.Web;
using System.Web.UI;
 
namespace UtilityLibrary
{
      public enum State
      {
            Application,Session,Cache,ViewState
      }
 
      public sealed class StateManager
      {
            private static readonly StateManagerobj = new 
            StateManager();
            private System.Web.UI.StateBagViewState = new StateBag();
                        
            private StateManager()
            {
              
            }
 
            static StateManager()
            {
                  
            }
 
            public static StateManager Instance
            {
                  get
                  {
                        return obj;
                  }
            }
 
            public void Add(string key,objectdata,State state)
            {
                  switch(state)
                  {
                        case State.Application: 
                       HttpContext.Current.Application.Add(key,data); 
                              break;
                        case State.Session: 
                       HttpContext.Current.Session.Add(key,data); 
                              break;
                        case State.Cache: 
                       HttpContext.Current.Cache.Insert(key,data); 
                              break;
                        case State.ViewState:ViewState.Add(key,data);
                              break;
                  }
            }
 
            public void Remove(string key,Statestate)
            {
                  switch(state)
                  {
                        case State.Application: 
                              if(HttpContext.Current.Application[key] 
                              != null)                            
                             HttpContext.Current.Application.
                              Remove(key); 
                              break;
                        case State.Session: 
                              if(HttpContext.Current.Session[key] != 
                              null)
                        
                             HttpContext.Current.Session.Remove(key); 
                              break;
                        case State.Cache: 
                              if(HttpContext.Current.Cache[key] != 
                              null)                         
                             HttpContext.Current.Cache.Remove(key); 
                              break;
                              caseState.ViewState: 
                              if(ViewState [key]!= null)
                              ViewState.Remove(key);
                              break;
                  }
            }
 
            public object Get(string key,Statestate)
            {
                  switch(state)
                  {
                        case State.Application: 
                              if(HttpContext.Current.Application[key] 
                              != null)
                              returnHttpContext.Current.
                              Application[key];
                              break;
                        case State.Session:
                              if(HttpContext.Current.Session[key] != 
                              null)
                              returnHttpContext.Current.Session[key];                                break;
                        case State.Cache: 
                              if(HttpContext.Current.Cache[key] != 
                              null)
                              returnHttpContext.Current.Cache[key];
                              break;
                        case State.ViewState: 
                              if(ViewState[key]!= null)
                                    returnViewState[key];
                              break;
                        defaultreturn null;
                  }
                  return null;
            }
 
            public int Count(State state)
            {
                  switch(state)
                  {
                        case State.Application: 
                              if(HttpContext.Current.Application!= 
                              null)
                              returnHttpContext.Current.Application.
                              Count;
                              break;
                        case State.Session: 
                              if(HttpContext.Current.Session!= null)
                              returnHttpContext.Current.Session.Count;
                              break;
                        case State.Cache: 
                              if(HttpContext.Current.Cache!= null)
                              returnHttpContext.Current.Cache.Count;
                              break;
                        case State.ViewState:
                              if(ViewState !=null)
                              returnViewState.Count;
                              break;
                        defaultreturn 0;
                  }
 
                  return 0;
            }
      }
}

The StateManager object in the above listing is static and readonly. A static readonly object can be instantiated only using a variable initializer or a static constructor.

It is to be noted that the C# compiler marks all types as beforefieldinit if they contain only non - static constructors. A laziness of a type depends on whether or not the type is marked as beforefieldinit. As shown in the example above, the static constructor is specified as it would be executed only once during the lifetime of the application and does not mark the type as beforefieldinit. This promises laziness. We do not require explicit locks in the example above, but it still is type safe. There is no requirement of checking whether the instance is null, as in the previous version of the StateManager class in Listing I.

Using the State Manager class

The following code shows how we can use the class designed above in our code.

Listing IV: Using the State Manager class

 
      private void Page_Load(object sender,System.EventArgs e)
            {
                  StateManager stateManager =StateManager.Instance;
                  stateManager.Add("jk","Joydip",State.Session);
                  if(stateManager.Get("jk",State.Session)!=null)
            }

 

 

Further Reading

Please refer to the following links for more related information:

http://www.dofactory.com/Patterns/PatternSingleton.aspx

http://www.yoda.arachsys.com/csharp/singleton.html

Conclusion

Design patterns are a solution to the complexities in software architecture. A good knowledge of design pattern goes a long way to solving the complexities that are faced in software designs. This article has discussed the Singleton Design Pattern, a pattern that falls under the Creational Patterns. Please send me your feedback.

 

 



User Comments

Title: Good article   
Name: .net nutter
Date: 2006-12-19 9:30:23 AM
Comment:
Well done for this article, sure most of us know about design patterns but clear, consise and real life examples are thin on the ground and your article is excellent for those new to this concept. Keep up the good work.
Title: very lucid example   
Name: Umed Singh Bisht
Date: 2006-09-11 2:25:53 AM
Comment:
This is crystal clear real time example...
.
10/10 to u
.
:)
Title: Fantastic   
Name: Ravi
Date: 2006-04-27 10:35:55 AM
Comment:
Great article with a solid real life example. I like you articles. Please write some more real life articles. good work.
Title: Very helpfull Article   
Name: Joydeep Adhikary
Date: 2006-04-26 1:01:57 PM
Comment:
Sir
Really it is very helpful for new comers in .Net world.
Pl. write & teach more.
Joydeep
Title: Innovations at Work   
Name: Nav
Date: 2006-04-26 5:49:34 AM
Comment:
Hello once again,

A Connection pool. A connection pool holds a fixed number of database connections. For ex say 10 connections ( which is configurable). So in other words, this connection pool holds only 10 instances of an object "Ten-ton". if it holds only two connections, then it is a doubleton. The callers of this class would need to wait to get hold of a connection.

www.codeproject.com/csharp/designpattern_doubleton.asp

Hope you got my point....
Please see my article at.....
Title: good article   
Name: Kay Lee
Date: 2006-04-25 6:54:40 PM
Comment:
Hi. Just read your article. Minus a few syntax errors in the second example, it's pretty much the basics of the singleton pattern.
Title: Author Response   
Name: Joydip
Date: 2006-04-25 4:36:07 AM
Comment:
Hi Nav,

Does doubleton pattern make any sense? What would be the purpose of such a pattern? Please come up with your innovations & views...
Title: Wonderful article   
Name: Ravi
Date: 2006-04-24 1:24:28 AM
Comment:
This is an excellant article. Keep it up. Thanks.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-26 3:52:16 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search