4
\$\begingroup\$

I did this as an exercise just to practice/improve using generics.

Independent of how useful this implementation of a Singleton is, how is my coding in terms of using generics and any other aspect of class design of code style?

void Main()
{
    var a = Singleton<MyClass>.Value;
    var b = Singleton<MyClass, MyClassFactory>.Value;
    var c = Singleton<MyClass>.Value;
    var d = Singleton<MyClass, MyClassFactory>.Value;
    var e = Singleton<MyOtherClass>.Value;
    var f = Singleton<MyOtherClass>.Value;
    var g = Singleton<MyOtherClass, MyOtherFactory>.Value;
    var h = Singleton<MyOtherClass, MyOtherFactory>.Value;
}

class SingletonBase
{
    protected static object Locker = new LockerObject();
}

class Singleton<T> : SingletonBase where T : new() 
{
    static T StaticT;

    public static T Value 
    {
        get
        {
            lock (Locker)
            {
                if(StaticT == null)
                {
                    StaticT = Activator.CreateInstance<Factory<T>>().Create();
                }
                else
                {
                    Console.WriteLine ("Singleton<T>::Value" + typeof(T).Name + " is already created");
                }
            }
            return StaticT;
        }
    }
}

class Singleton<T, F> : SingletonBase where T : new() where F : IFactory<T>, new()
{
    static T StaticT;

    public static T Value 
    {
        get
        {
            lock (Locker)
            {
                if(StaticT == null)
                {
                    StaticT = new F().Create();
                }
                else
                {
                    Console.WriteLine ("Singleton<T, F>::Value" + typeof(T).Name + " is already created");
                }
            }
            return StaticT;
        }
    }
}

class LockerObject
{
    Guid myGUID;
    public LockerObject()
    {
        this.myGUID = Guid.NewGuid();
        Console.WriteLine ("New LockerObject " + this.myGUID.ToString());
    }
}

interface IFactory<T>
{
    T Create();
}

class Factory<T> : IFactory<T> where T : new()
{
    public T Create()
    {
        Console.WriteLine ("Factory<T>::Create()");  
        return new T();
    }
}

class MyClassFactory : IFactory<MyClass>
{
    public MyClass Create()
    {
        Console.WriteLine ("MyClassFactory::Create()");    
        return new MyClass();
    }
}

class MyClass
{
    public MyClass()
    {
        Console.WriteLine ("MyClass created");
    }
}


class MyOtherClass
{
    public MyOtherClass()
    {
        Console.WriteLine ("MyOtherClass created");
    }
}

class MyOtherFactory : IFactory<MyOtherClass>
{
    public MyOtherClass Create()
    {
        Console.WriteLine ("MyOtherFactory::Create()");    
        return new MyOtherClass();
    }
}

Output:

New LockerObject 36aa2282-d745-43ca-84d2-998a78e39d51
Factory<T>::Create()
MyClass created
MyClassFactory::Create()
MyClass created
Singleton<T>::ValueMyClass is already created
Singleton<T, F>::ValueMyClass is already created
\$\endgroup\$
4
  • 2
    \$\begingroup\$ a little offtopic: those are not singletons. As long as class T is required to have a public parameterless constructor, anyone can create a new instance of it. Same problem with the version using IFactory<T>. \$\endgroup\$ Commented May 23, 2012 at 7:47
  • \$\begingroup\$ understood, good point. I was only designing it for code that makes the assumption that a DI container is able to control all object instantiation... \$\endgroup\$ Commented May 23, 2012 at 15:34
  • \$\begingroup\$ Does this design assure in multithreading case it creates only one object of this class? \$\endgroup\$ Commented Oct 17, 2012 at 4:45
  • \$\begingroup\$ Have a read of csharpindepth.com/Articles/General/Singleton.aspx \$\endgroup\$
    – dreza
    Commented Jul 7, 2013 at 20:33

1 Answer 1

3
\$\begingroup\$

About your locking strategy to create the singleton, I would use a double check to avoid too much locking:

if(x)
{
    lock(Locker)
        if(x) //again once we got the lock
            DoStuff();
} 
else 
{
    FooBar();
}

Like this, you will hopefully use the lock only once when you first call the instance.

\$\endgroup\$
4

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.