Expiry of a Singleton instance after a period of time

Putting aside arguments for the relative virtues and disvirtues of the Singleton pattern so far, and given that a Singleton is generally considered to be an instance that persists for the life of an application, what would be the best way to go about having a Singleton that has a limited life?

Is there anything amiss with something like the following:

public class CategoryHandler
{    

    private static DateTime m_expires;

    public bool HasExpired
    {
        get return DateTime.Now > m_expires;
    }

    private CategoryHandler()
    {
        m_expires = DateTime.Now.AddMinutes(60);
    }

    public static CategoryHandler Instance()
    {
        if(HasExpired)
        {
            //Dispose and reconstruct
        }
        else
        {
            //Use existing instance
        }
    }

}

      

Or is there a much better way to approach this problem?

+2


source to share


5 answers


To ensure thread safety, you need some kind of blocking:



public sealed class CategoryHandler
{
    private static CategoryHandler _instance = null;
    private static DateTime _expiry = DateTime.MinValue;
    private static readonly object _lock = new object();

    private CategoryHandler() { }

    public static bool HasExpired
    {
        get
        {
            lock (_lock) { return (_expiry < DateTime.Now); }
        }
    }

    public static CategoryHandler Instance
    {
        get
        {
            lock (_lock)
            {
                if (HasExpired)
                {
                    // dispose and reconstruct _instance
                    _expiry = DateTime.Now.AddMinutes(60);
                }
                return _instance;
            }
        }
    }
}

      

+3


source


The only major problem I see is that another class is already referencing the old instance, this will not invalidate it. So while all classes are doing this:

CategoryHandler.Instance.Method();

      

but not



CategoryHandler singleton = CategoryHandler.Instance;
...
singleton.SomeMethod();

      

you should be fine if you are happy that the singleton will expire on the next call, and not in sixty minutes.

If you need it to expire exactly after a certain amount of time, you will need to use a timer and replace the instance in the callback method (beware that the timer will callback in another thread, so be sure to implement a thread safe singleton pattern)

+2


source


To avoid problems with classes that reference the old instance, you might consider creating a cache wrapper for your class. The fist will retrieve the ICategoryHandler interface, suppose it looks like this:

interface ICategoryHandler 
{
  int A();
}

      

and then you implement the wrapper (lock omitted):

class CategoryHandlerWrapper : ICategoryHandler
{
  ICategoryHandler instance;
  private DateTime expiry = DateTime.MinValue;

  public int A()
  {
    return Instance().A();
  }

  public bool HasExpired
    {
        get return DateTime.Now > expiry;
    }

  private CategoryHandler Instance()
    {
        if(HasExpired)
        {
            //Dispose and reconstruct
        }
        else
        {
            //Use existing instance
        }
    }
}

      

This way you can use normal dependency injection and still use the function you are using. Also the issue with old links is encapsulated in one place.

+1


source


Have you considered using the IoC / DI Container framework and "singleton" lifetime management?

Microsoft Unity is the one I'm most familiar with, and they don't provide a LifetimeManager out of the box, does exactly what you want to do. However, you can create your own child; see Writing Custom Lifecycle Managers .

Or you can look at other structures and see if you have what you want in the box.

EDIT: Please note that this still won't get you out of the "trapped" problem Martin was talking about.

+1


source


What exactly do you want to achieve with the expiring single? I think you are in design trouble if you really want to. And as Martin said, you will have problems if some code "hijacks" you in a single instance.

So what exactly do you use for this? Or is it just a question of curiosity?

0


source







All Articles