/// <summary> /// Generic Single base classes /// </summary> public class ServiceSingletonBase<T> where T : class, new() { private static volatile T _instance = null; private static readonly object _lock = new object(); public static T Instance { get { if (_instance == null) { lock (_lock) { if (_instance == null) _instance = new T(); } return _instance; } else return _instance; } } }
class MyClass : ServiceSingletonBase<MyClass> { protected|private|internal MyClass() { } }
so what if I want to make a class which 1) is a singleton, 2) which behaves like a dictionary
you have two options, you can inherit your class from the SingletonBase class, and then you can implement IDictionary<TKey, Tvalue> and delegate all works to the inner dictionary object. an alternative option is to inherit from the Dictionary<TKey, TValue> class and then try to implement the pattern required by the singleton class.
neither sound ideal... You cannnot reuse code fully (you have to either simulate the interface or you will need to write boilerplate/run-of-the-mill singleton pattern code). And you are bound by the single-inheritance-rule by C#.
however, with the help of wrapper by combining inheritance and composition, you might write someting like this
class MyClassWrapper : Singleton<MyClassWrapper> { { MyClass _myClass = new MyClass() public MyClass MyClass { get { return _myClass; } } } MyClass : Dictionary<string, TableId> { } class TableId { public string Name {get; set;} public int InnerId { get; set; } }
this way, you can call MyClassWrapper.Instance.MyClass and use MyClassWrapper.Instance.MyClass in places where Dictionary is used....
Now, we project our eyes back to the composition, but instead, we shall make MyClassWrapper implement IDictionary<Tkey, TValue>, so the code beomes:
class MyClassWrapper : Singleton<MyClassWrapper>, IDictionary<string, TableId> { { MyClass _myClass = new MyClass(); // public MyClass MyClass { get { return _myClass; } } public Add(string key, TableId tableId) { _myClass.Add(string, tableId); } } public Remove(string key) { _myClass.Remove(key); } public this[string key] { get { return _myClass[key]; } set { _myClass[key] = value; } } //... } MyClass : Dictionary<string, TableId> {} // omitted
this sound tedious, but at least you can inject some code such as
class MyClassWrapper : Singleton<MyClassWrapper>, IDictionary<string, TableId> { { // ... Dictionary<int, TableId> _inverseTable; public Add(string key, TableId tableId) { _myClass.Add(string, tableId); _inverseTable[talbeId] = tableId; } } public Remove(string key) { _myClass.Remove(key); /* similar things here */ } public this[string key] { get { return _myClass[key]; /* similar things here */ } set { _myClass[key] = value; /* additional things here*/ } } //... } MyClass : Dictionary<string, TableId> {} // omitted
the benefit is that you can use MyClassWrapper.Instance[key] = new TableId { ... }; but still we did not cut down the code we need to write.
class MyClassWrapper : Singleton<MyClassWrapper> { { // ... private MyClass _myClass; public IDictionary<string, TableId> MyClass { get { return _myClas; } } } class MyClass : Dictionary<string, TableId>, IDictionary<string, TableId> { Dictionary<int, TableId> _inverseTable; IDictionary<string, TableId>.Add(string key, TableId tableId) { base.Add(string, tableId); _inverseTable[talbeId] = tableId; } } IDictionary<string, TableId>.Remove(string key) { base.Remove(key); /* similar things here */ } IDictionary<string, TableId>.this[string key] { get { return base[key]; /* similar things here */ } set { base[key] = value; /* additional things here*/ } } //... } // omitted
this is based on the assumption that we might only override part of the IDictionary interface. we inherit MyClass from Dictionary<string, TableId> so we can reuse most of the impl, and we implements IDictionary<string, tableId> so we cast it explicitly back to IDictionary<string, tableId>, we get the explicit implemented IDictionary<string, TableId>; and see that we have IDictionary<string, TableId> in the MyClassWrapper.
but still there is a bit cubersome in that you have to call. like MyClassWrapper.Instance.MyClass... still not good.
then, we know there is something called converter...
however, there is limitation on the converter (we will implement the with implicit or explicit operator), so this is illegal in C#.
public static implicit operator IDictionary<string, TableId>(MyClassWrapper instance) { return instance._myclass; }
public class MyClassWrapper : Singleton<MyClassWrapper> { private MyClass _myclass = new MyClass(); public static implicit operator MyClassBase(MyClassWrapper instance) { return instance._myclass; } } public abstract class MyClassBase : Dictionary<string, TableId> { protected Dictionary<int, TableId> _inverseTable = new Dictionary<int,TableId>(); public abstract void Add(string key, TableId value); public abstract bool Remove(string key); public abstract TableId this[string key] { get; set; } } public class MyClass : MyClassBase { public override void Add(string key, TableId value) { ((Dictionary<string, TableId>)this).Add(key, value); _inverseTable.Add(value.InnerId, value); } public override bool Remove(string key) { Dictionary<string, TableId> baseDict = ((Dictionary<string, TableId>)this); if (baseDict.ContainsKey(key)) { var id = baseDict[key].InnerId; _inverseTable.Remove(id); return baseDict.Remove(key); } return false; } public override TableId this[string key] { get { Dictionary<string, TableId> baseDict = ((Dictionary<string, TableId>)this); return baseDict[key]; } set { Dictionary<string, TableId> baseDict = ((Dictionary<string, TableId>)this); if (baseDict.ContainsKey(key)) { var id = baseDict[key].InnerId; _inverseTable[id] = value; } } } }now, what you cando with the new instance is like this:
((MyClassBase)MyClassWrapper.Instance).Add("1", new TableId { InnerId = 1, Name = "1" }) ; Console.WriteLine("value = {0}", ((MyClassBase)MyClassWrapper.Instance)["1"].InnerId);so, the cast is needed. but we have avoided the property acces. However, we have some potential risk, since user can tell the base class is a Dictionary<string, TableId>, and if such an conversion is attempted.
Dictionary<string, TableId> potentialRisk = ((Dictionary<string, TableId>)(MyClassBase) MyClassWrapper.Instance);
You will risk yourself of inconsisitence.
Actually we shall create an interface which has a clone of parts of the Dictionary methods. which can server better hide cast from being misused (actually we still cannot prevent it from casting, because the real object is known at runtime), we shall see this technique in next post - simulating/imitate interface.
In the end of the post, actually there is a very interesting use of the Singleton base class that we have. so instead of Singleton<MyClassWrapper> we directl
public class MyClassWrapper : Singleton<MyClass> { // } // the Definition of MyClass, MyClassBase is the same as we have seen before.Though it saves us a log of trouble, it still have the trouble of exposing dangerous the internals to inadvent uses.