Singleton mode is one of the most common design patterns, and we often write such code. Because the basic principle is to save a static object instance, we can use generics to write out a generic singleton class.
The code is simple:
public class Singleton<T>
...{
static readonly T _t;
static Singleton()
...{
_t = Construct();
}
public static T GetInstance()
...{
return _t;
}
private static T Construct()
...{
Type type = typeof(T);
ConstructorInfo ctor;
ctor = type.GetConstructor(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic,
null, new Type[0], new ParameterModifier[0]);
System.Diagnostics.Debug.Assert(ctor != null, "Error in ENLS.Basic.Singleton.Construct().");
return (T)ctor.Invoke(new object[0]);
}
}
Because the special generic classes are different types,singleton<tuple<int>> and singleton<tuple<int,long>> are different, so the _ in these two classes T is a different static instance. Then the new instance is created by invoking a common or private default constructor parameter in the construct method. Why is there a public constructor? This is to use the Nullobject mode. For example, for the sake of convenience, I want to add a method to the tuple base class to the Null object
public static Tuple GetNullInstance<_Tuple>() where _Tuple: Tuple
{
return Singleton<_Tuple>.GetInstance();
}
With this empty object, I can simply use the function that iterates through the control described in the previous article.
public IEnumerable<Control> Iterator<_Tuple>(Control baseCtl) where _Tuple : Tuple
...{
Tuple tuple = Tuple.GetNullInstance<_Tuple>();
foreach(Control c in baseCtl.Controls)
...{
if (!tuple.HasType(c))
...{
foreach (Control c1 in Iterator<_Tuple>(c))
yield return c1;
}
else
yield return c;
}
}
This makes it easy to call the
foreach (Control c in this.Iterator<Tuple<TextBox, TreeView, CheckBox>>(this))
MessageBox.Show(c.Name);