AspAlliance.com LogoASPAlliance: Articles, reviews, and samples for .NET Developers
URL:
http://aspalliance.com/articleViewer.aspx?aId=810&pId=-1
Implementing a Singleton Pattern in C#
page
by Joydip Kanjilal
Feedback
Average Rating: 
Views (Total / Last 10 Days): 11760/ 15

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.

 

 



©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-05-08 6:02:46 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search