There can be only one
There are some object we want to share system wide
• Expensive to Create
• Represent a single instance entity
• Shared State
• Database connection
Example
• Cache
• Logging
• Database connection
1st Solution
So by making constructor private, we insure that the class cannot be instantiated in any other way except by accessing the Current property.
Issue with the above solution
• Since static types lack some of the more useful oo features like polymorphism
Next Approach
Here the class is not marked as Static and also there is only one way to obtain an instance outside the class.
Issue
When does the instance of Cache gets created?
If a class does not have a static constructor then it is marked 'BeforeFieldInit'. In this
circumstance, according to the ECMA spec "If marked BeforeFieldInit then the type's
initializer method is executed at, or sometime before, first access to any static field
defined for that type", this is a loose guarantee. It means that there is no guarantee when
the initializer is run, it could be when the type is loaded, when the first static method is
called or when the field itself is accessed.
If an exception fires during the construction of the object this exception is held and re-thrown on first use of the type
Lazy Initialization
By explicitly adding a static constructor this changes the behavior of the CLR to perform lazy initialization, so the logger instance is not created until we actually need it.A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
Lazy Initialization By Hand
Issue
The above code only guaranteed if running in a single threaded environment or in other word its not thread safe.
Thread Safe Lazy Initialization
In the above code after the initial creation has happended the lock statement will never be executed.
Few Important Points on Singleton
• .Net singelton is scoped on an App Domain not process
• Singleton objects live forever so if they are expensive in terms of memory footprint they will continue to do so until the application dies as the type itself holds on to a strong reference.
• Hard to derive with. You can’t easily derive from a singleton since the constructor is private and thus the type is effectively sealed, making the constructor protected can offer some possibility of deriving from it although the derived class will not be able to have a private constructor.
There are some object we want to share system wide
• Expensive to Create
• Represent a single instance entity
• Shared State
• Database connection
Example
• Cache
• Logging
• Database connection
1st Solution
public static class Cache { private static Cache cache = new Cache(); private Cache() {} public static Cache Current { get { return cache; } } public static void AddToCache(Object o, Object key) { //Write logic to add to cache } public static object GetFromCache(Object key) { //Write logic to add to cache } } Cache.Current.AddToCache(o,key) Cache.Current.GetFromCache(key)
So by making constructor private, we insure that the class cannot be instantiated in any other way except by accessing the Current property.
Issue with the above solution
• Since static types lack some of the more useful oo features like polymorphism
Next Approach
public class Cache { private static Cache cache = new Cache(); private Cache() { } public static Cache Current { get { return cache; } } public static void AddToCache(Object o, Object key) { //Write logic to add to cache } public static object GetFromCache(Object key) { //Write logic to add to cache } } Cache.Current.AddToCache(o,key) Cache.Current.GetFromCache(key)
Here the class is not marked as Static and also there is only one way to obtain an instance outside the class.
Issue
When does the instance of Cache gets created?
If a class does not have a static constructor then it is marked 'BeforeFieldInit'. In this
circumstance, according to the ECMA spec "If marked BeforeFieldInit then the type's
initializer method is executed at, or sometime before, first access to any static field
defined for that type", this is a loose guarantee. It means that there is no guarantee when
the initializer is run, it could be when the type is loaded, when the first static method is
called or when the field itself is accessed.
If an exception fires during the construction of the object this exception is held and re-thrown on first use of the type
Lazy Initialization
public class Cache { private static Cache cache; static Cache() { cache = new Cache(); } public static Cache Current { get { return cache; } } public static void AddToCache(Object o, Object key) { //Write logic to add to cache } public static object GetFromCache(Object key) { //Write logic to add to cache } } Cache.Current.AddToCache(o,key) Cache.Current.GetFromCache(key)
By explicitly adding a static constructor this changes the behavior of the CLR to perform lazy initialization, so the logger instance is not created until we actually need it.A static constructor is called automatically to initialize the class before the first instance is created or any static members are referenced.
Lazy Initialization By Hand
public class Cache { private static Cache cache = null; static Cache(){} public static Cache Current { if (cache == null) cache = new Cache(); return cache; } public static void AddToCache(Object o, Object key) { //Write logic to add to cache } public static object GetFromCache(Object key) { //Write logic to add to cache } } Cache.Current.AddToCache(o,key) Cache.Current.GetFromCache(key)
Issue
The above code only guaranteed if running in a single threaded environment or in other word its not thread safe.
Thread Safe Lazy Initialization
public class Cache { private static Cache cache = null; private static Object initLock = new object(); static Cache(){} public static Cache Current { if (cache == null) { CreateInstance(); } return cache; } private static void CreateInstance() { lock(initLock){ if (cache == null) cache = new Cache(); } } public static void AddToCache(Object o, Object key) { //Write logic to add to cache } public static object GetFromCache(Object key) { //Write logic to add to cache } } Cache.Current.AddToCache(o,key) Cache.Current.GetFromCache(key)
In the above code after the initial creation has happended the lock statement will never be executed.
Few Important Points on Singleton
• .Net singelton is scoped on an App Domain not process
• Singleton objects live forever so if they are expensive in terms of memory footprint they will continue to do so until the application dies as the type itself holds on to a strong reference.
• Hard to derive with. You can’t easily derive from a singleton since the constructor is private and thus the type is effectively sealed, making the constructor protected can offer some possibility of deriving from it although the derived class will not be able to have a private constructor.
No comments:
Post a Comment