首页 > 解决方案 > 是否可以在程序退出时强制 C# 终结器在 .NET Core 中运行?

问题描述

我有一个 .NET Core C# 类,它包装了一个非托管指针,它应该在程序退出时与其他资源清理一起被释放。但是,没有调用析构函数。我在调试和发布模式下都试过了。我看到 .NET Core 显然不能保证会运行析构函数,那么推荐的解决方法是什么?IMO 垃圾收集的主要目的是避免让开发人员跟踪引用,所以我觉得这种行为令人惊讶,至少可以这么说。

来自 MSDN:在 .NET Framework 应用程序中(但不在 .NET Core 应用程序中),程序退出时也会调用终结器。

public Demo { 
  IntPtr _ptr;

  public Demo() 
  { 
    Console.WriteLine("Constructor");
    _ptr = /* P-invoke external function */ 

  ~Demo 
  {
    Console.WriteLine("Destructor");
    /*P-invoke ptr deletion */
  }
}

public static void Main() 
{ 
  Demo demo = new Demo();
  demo = null;
  GC.Collect();
}

程序输出:

Constructor
<...>\Test.exe (process 7968) exited with code 0.

标签: c#.net-core

解决方案


需要进行更多更改以提高调用终结器的可能性。

顺便说一句,Finalizer 永远不能保证被调用。如果要保证资源释放,请在应用/方法/代码块退出前实现IDisposable并调用。Dispose()此外,确保在退出代码块、使用或语句Dispose()之前调用(即使应用程序崩溃,FailFast 和 StackOverflow 除外) 。try-finallyusing

这是一个可以玩的例子。

public class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("[main] Constructing");
        MyDisposable m = new MyDisposable(0);
        MyMethod(1);
        Console.WriteLine("[main] Disposing [object 0]");
        m.Dispose();
        Console.WriteLine("[main] GC Collecting");
        GC.Collect();
        GC.WaitForPendingFinalizers();
        Console.WriteLine("[main] Done");
        Console.ReadKey();
    }

    private static void MyMethod(int i)
    {
        new MyDisposable(i);
    }
}

public class MyDisposable : IDisposable
{
    private int _id;

    public MyDisposable(int id)
    {
        _id = id;
        Console.WriteLine($"[object {_id}] Constructed");
    }

    private bool disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                Console.WriteLine($"[object {_id}] Disposing by Dispose()");
            }
            else
            {
                Console.WriteLine($"[object {_id}] Disposing by ~Finalizer");
            }
            Console.WriteLine($"[object {_id}] Disposed");
            disposed = true;
        }
        else
            Console.WriteLine($"[object {_id}] Already disposed!");
    }

    ~MyDisposable()
    {
        Dispose(false);
    }
}

输出

[main] Constructing
[object 0] Constructed
[object 1] Constructed
[main] Disposing [object 0]
[object 0] Disposing by Dispose()
[object 0] Disposed
[main] GC Collecting
[object 1] Disposing by ~Finalizer
[object 1] Disposed
[main] Done

一些阅读:使用实现 IDisposable 的对象


推荐阅读