50

I have a class with extensive static members, some of which keep references to managed and unmanaged objects.

For instance, the static constructor is called as soon as the Type is referenced, which causes my class to spin up a blockingQueue of Tasks. This happens when one of the static methods is called, for example.

I implemented IDisposable, which gives me methods to handle disposal on any instance objects I created. However, these methods are never called if the consumer doesn't create any instance objects from my class.

How and where do I put code to dispose of references maintained by the static portion of my class? I always thought that disposal of static-referenced resources happened when the last instance object was released; this is the first time I've ever created a class where no instances may ever be created.

2
  • 3
    Static items are available for the entire execution of the application. You don't create static items by using the NEW keyword, so this means you don't have multiple instances of anything, because you actually don't instantiate anything. About managed objects, don't worry about them, the GC will take care of them. About unmanaged resources try to use them in a non static class, or they will be kept until you close your application. Static items don't support dispose. Commented Aug 25, 2012 at 23:57
  • 1
    Is it reliable that statically referenced unmanaged resources will be released when the app exits? Let's say I have an OpenGL or OpenAL context that I want to just keep around until the app exits. Is there any reason not to just have a static class member reference to that context? Commented Nov 30, 2022 at 23:38

5 Answers 5

67

The static variable of your class are not garbage collected until the app domain hosting your class is unloaded. The Dispose() method will not be called, because it is an instance method, and you said that you wouldn't create any instances of your class.

If you would like to make use of the Dispose() method, make your object a singleton, create one instance of it, and dispose of it explicitly when your application is about to exit.

public class MyClass : IDisposable {
    public IList List1 {get; private set;}
    public IDictionary<string,string> Dict1 {get; private set;}
    public void Dispose() {
        // Do something here
    }
    public static MyClass Instance {get; private set;}
    static MyClass() {
        Instance = new MyClass();
    }
    public static void DisposeInstance() {
        if (Instance != null) {
            Instance.Dispose();
            Instance = null;
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Is this instance not garanteed to garbage collected + disposed when the application exit ?
@Alsatian no, it's not guaranteed. GC will try its best to run pending finalizers, but if there's a timeout, it gives up and exits.
10
public class Logger : IDisposable
{

    private string _logDirectory = null;
    private static Logger _instance = null;

    private Logger() : this(ConfigurationManager.AppSettings["LogDirectory"])
    {
        AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
    }

    private Logger(string logDirectory) 
    {
    } 

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

    private void CurrentDomain_ProcessExit(object sender, EventArgs e)
    {
        Dispose();
    }



    public void Dispose()
    {
        // Dispose unmanaged resources
    }
}

Comments

0

You should dispose this objects manually, there is no way to create a "finalizer" for static resources.

7 Comments

How would I dispose of them manually? How will I be notified that I need to do this?
@Joe That is entirely up to you to decide. Only you know when it's time to call Dispose of something that is statically held.
For instance, see the example in original question, where I spin up a blockingQueue of Actions. This queue should run until the user no longer wants to drop Actions into it (via static method). Let me make that more clear; when do I kill off the task that drains that queue? So, when do I kill it? How will I know my class is no longer in "scope" to the user?
@Joe You can for example use static integer variable to store resource consumers count (increment/decrement it via Interlocked class in constructor/destructor/dispose method).
Let me clarify all of my edits above. In particular, I maintain a blockingQueue of Actions for a logger. When a user wants to have something logged, he calls my static method Log, and I drop an Action into the blockingQueue that calls the logger. I have a separate Task, created by my static constructor, which drains this queue. This queue and the task that drain it should remain in place "forever", or at least until my assembly is unloaded. So - when do I kill off this Task? Is there some notification that my assembly is no longer needed, so I can clean up the other (unmanaged) resources?
|
-1

If you really want to have static members which keep references to unmanaged objects just create a method for disposing the unmanaged objects and "force" consumer to use it on exit.

By "force" I mean document your class with a paragraph that states "when" and "why" to use this "dispose" method. Do it either if you are the sole consumer (or your code...) or you plan to distribute your class. Also try to use a somehow descriptive name (to that "dispose" method) such as "DisposeStatics", "AlwaysDispose", "DisposeAtEnd" etc.

Comments

-2

If you want to maintain the static class and you believe no one will ever need to understand the internal workings of the class, you can place a singleton class with IDisposable inside of your static class and place any members that require disposing in the singleton. Then simply reference the singleton members from members in the static of the same name.

public static class AStaticClass
{
    public static object PropertyThatNeedsSpecialDisposal
    {
        get { return DisposableInnerClass.Instance.PropertyThatNeedsSpecialDisposal; }
    }

    protected internal class DisposableInnerClass : IDisposable
    {
        public int PropertyThatNeedsSpecialDisposal = 42;
        private static readonly object locker = new object();

        private static DisposableInnerClass? _instance = null;

        private DisposableInnerClass()
        { }

        ~DisposableInnerClass()
        {
            Dispose();
        }

        internal static DisposableInnerClass Instance
        {
            get
            {
                if (_instance is null)
                {
                    lock (locker)
                    {
                        if (_instance is null)
                        {
                            _instance = new DisposableInnerClass();
                        }
                    }
                }
                return _instance;
            }
        }

        public void Dispose()
        {
            //dispose of PropertyThatNeedsSpecialDisposal here
        }
    }
}

4 Comments

...and when do you dispose that internal class?
When the appdomain tries to unload the singleton the dispose method is called.
First off, there are no AppDomains in .NET Core (and most .NET Framework apps have only one domain, and it gets unloaded at process exit, so this is pointless). Secondly, this depends on a finalizer, which is incredibly unreliable.
You're assuming .netcore buddy. I don't understand why you are parading around with such a huge chip on your shoulder. That is not what this community is about.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.