14

I have a singleton that uses the "static readonly T Instance = new T();" pattern. However, I ran into a case where T is disposable, and actually needs to be disposed for unit tests. How can I modify this pattern to support a disposable singleton?

The interface I would like is something like:

var x = Foo.Instance;
var y = Foo.Instance; // x == y
...
x.Release(); // this causes the next Foo.Instance to return a fresh object
             // also, it assumes no further operations on x/y will be performed.

Note - the pattern has to be thread-safe, of course.

Edit - for the purpose of production code, this is a true singleton. The thing is that it locks some files, and so for cleanup in unit tests we have to dispose it.

I would also prefer a pattern that can be reused, if possible.

ripper234
  • 222,824
  • 274
  • 634
  • 905
  • If you can do new T() that means you must have a generic constraint of T having a public parameterless constructor - in which case it's not a singleton to start with. – Jon Skeet Oct 22 '08 at 13:30
  • I just wrote it as a pattern, it's not really generic right now at all. What I do have is a class that calls its private constructor and assigns it to the public static readonly field. – ripper234 Oct 22 '08 at 13:32

8 Answers8

15

At that point I don't think I'd really consider it to be a singleton any more, to be honest.

In particular, if a client uses a singleton they're really not going to expect that they have to dispose of it, and they'd be surprised if someone else did.

What's your production code going to do?

EDIT: If you really, really need this for unit tests and only for unit tests (which sounds questionable in terms of design, to be frank) then you could always fiddle with the field using reflection. It would be nicer to work out whether it should really be a singleton or whether it should really be disposable though - the two very rarely go together.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • It's an object that I would like to have only one in my system, and that holds some unmanaged resources (e.g. files). – ripper234 Oct 22 '08 at 13:50
  • Personally I'd pass it in to the things which need it, avoiding the problem to start with. The singleton pattern is severely limited when it comes to this kind of thing - it's a test killer. But given the design as cast in stone, go with the hacky reflection solution to replace the instance. – Jon Skeet Oct 22 '08 at 14:14
  • These days, "fiddle using reflection" simplifies to "use PrivateObject", everything else still applies. – Jirka Hanika Jul 16 '19 at 15:31
13

Mark Release as internal and use the InternalsVisibleTo attribute to expose it only to your unit testing assembly. You can either do that, or if you're wary someone in your own assembly will call it, you can mark it as private and access it using reflection.

Use a finalizer in your singleton that calls the Dispose method on the singleton instance.

In production code, only the unloading of an AppDomain will cause the disposal of the singleton. In the testing code, you can initiate a call to Release yourself.

Omer van Kloeten
  • 11,800
  • 9
  • 42
  • 53
5

Singletons should not be Disposable. Period. If someone calls Dispose prematurely, your application is screwed until it restarts.

jezell
  • 2,532
  • 14
  • 12
  • 11
    There are NO absolutes in software engineering save there are no absolutes in software engineering. When you come to grips with this, you will be a better engineer... – iGanja Dec 21 '13 at 21:11
  • 1
    Hello HttpClient. Disposable that must be singleton also. – David Burg Jan 11 '21 at 01:32
2
 public class Foo : IDisposable
  { [ThreadStatic] static Foo _instance = null;

    private Foo() {IsReleased = false;}

    public static Foo Instance
     { get
        { if (_instance == null) _instance = new Foo();
          return _instance;
        }
     }

    public void Release()
     { IsReleased = true;
       Foo._instance = null;
     }

    void IDisposable.Dispose() { Release(); }

    public bool IsReleased { get; private set;}

  }
Mark Cidade
  • 98,437
  • 31
  • 224
  • 236
0

You could use a nested lazy singleton (See here) with some simple modifications:

public sealed class Singleton : IDisposable
{
    Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (!Nested.released)
                return Nested.instance;
            else
                throw new ObjectDisposedException();
        }
    }

    public void Dispose()
    {
         disposed = true;
         // Do release stuff here
    }

    private bool disposed = false;

    class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
}

Remember to throw ObjectDisposedException in all public methods/properties of the object if it has been disposed.

You should also, provide a finalizer method for the object, in case Dispose doesn't get called. See how to correctly implement IDisposable here.

Bogdan Maxim
  • 5,866
  • 3
  • 23
  • 34
0

If the class implements IDisposable (as you imply it does) then just call x.Dispose()

Jon Grant
  • 11,369
  • 2
  • 37
  • 58
0

For unit tests you could use a "manual" instance (but you would need a way to instantiate the object).

In your case, probably you should better use the factory pattern (abstract/method - whichever is the best for your case), combined with a singleton.

If you want to test if the singleton has disposed properly of the used objects (in unit test), then use the Factory method, otherwise use the singleton pattern.

By the way, if you don't have access to the singleton source code or you are not allowed to modify it, you would better wrap it to another singleton, and provide all the logic from the new one (more like a proxy). It sounds like overkill, but it could be a viable solution.

Also, in order to be able to control the access to it, provide a factory, and let the clients get the new object only if the object hasn't been disposed.

Bogdan Maxim
  • 5,866
  • 3
  • 23
  • 34
0

Another option to make a disposable Singleton is to use SandCastle's [Singleton] atribute for your class, then Castle framework takes care of disposing all disposable Singleton objects

Boris Lipschitz
  • 9,236
  • 5
  • 53
  • 63