【问题标题】:How and when are c# Static members disposed?c# 静态成员是如何以及何时处置的?
【发布时间】:2023-04-01 05:24:01
【问题描述】:

我有一个包含大量静态成员的类,其中一些保留对托管和非托管对象的引用。

例如,一旦引用了 Type,就会调用静态构造函数,这会导致我的类启动任务的阻塞队列。例如,当调用其中一个静态方法时会发生这种情况。

我实现了 IDisposable,它为我提供了处理我创建的任何实例对象的处置方法。但是,如果使用者没有从我的类中创建任何实例对象,则永远不会调用这些方法。

如何以及在何处放置代码来处理由我的类的静态部分维护的引用?我一直认为静态引用资源的处理是在最后一个实例对象被释放的时候发生的;这是我第一次创建一个不能创建实例的类。

【问题讨论】:

  • 静态项可用于应用程序的整个执行。您不使用 NEW 关键字创建静态项目,因此这意味着您没有任何东西的多个实例,因为您实际上没有实例化任何东西。关于托管对象,不要担心它们,GC 会处理它们。关于非托管资源尝试在非静态类中使用它们,否则它们将一直保留到您关闭应用程序为止。静态项目不支持 dispose。

标签: c# .net dispose idisposable


【解决方案1】:

在卸载托管您的类的应用程序域之前,您的类的静态变量不会被垃圾收集。 Dispose() 方法不会被调用,因为它是一个实例方法,并且你说过你不会创建你的类的任何实例。

如果您想使用Dispose() 方法,请将您的对象设为单例,创建它的一个实例,并在您的应用程序即将退出时显式处理它。

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;
        }
    }
}

【讨论】:

    【解决方案2】:
    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
        }
    }
    

    【讨论】:

      【解决方案3】:

      您应该手动处理这些对象,没有办法为静态资源创建“终结器”。

      【讨论】:

      • 我将如何手动处理它们?我将如何收到我需要这样做的通知?
      • @Joe 这完全由您决定。只有你知道什么时候该调用 Dispose 来处理静态持有的东西。
      • 例如,请参阅原始问题中的示例,我在其中启动了一个操作的阻塞队列。该队列应该一直运行到用户不再想要将操作放入其中(通过静态方法)。让我更清楚地说明这一点;我什么时候终止耗尽该队列的任务?那么,我什么时候杀死它?我如何知道我的课程不再在用户的“范围”内?
      • @Joe 例如,您可以使用静态整数变量来存储资源消费者计数(通过构造函数/析构函数/dispose 方法中的Interlocked 类增加/减少它)。
      • 让我澄清一下我上面的所有编辑。特别是,我为记录器维护了一个操作的阻塞队列。当用户想要记录某些内容时,他调用我的静态方法 Log,然后我将一个 Action 放入调用记录器的阻塞队列中。我有一个单独的任务,由我的静态构造函数创建,它耗尽了这个队列。这个队列和消耗它的任务应该“永远”保持在原地,或者至少直到我的程序集被卸载。所以 - 我什么时候结束这个任务?是否有一些通知表明不再需要我的程序集,以便我可以清理其他(非托管)资源?
      【解决方案4】:

      如果你真的想拥有保留对非托管对象的引用的静态成员 只需创建一个方法来处理非托管对象并“强制”消费者在退出时使用它。

      “强制”是指用一段说明“何时”和“为什么”使用此“处置”方法的段落来记录您的课程。 如果您是唯一的消费者(或您的代码......)或者您计划分发您的课程,请执行此操作。 还可以尝试使用某种描述性名称(对于“dispose”方法),例如“DisposeStatics”、“AlwaysDispose”、“DisposeAtEnd”等。

      【讨论】:

        猜你喜欢
        • 2016-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-09-30
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        相关资源
        最近更新 更多