什么是析构函数
析构函数(Destructor),在 C#中也称为终结器(Finalizer),是一种特殊的方法,用于在对象被垃圾回收器回收之前执行清理操作。析构函数为托管代码提供了一种在对象生命周期结束时执行必要清理工作的机制。
析构函数的语法特征
1 2 3 4 5 6 7 8 9
| public class MyClass { ~MyClass() { Console.WriteLine("MyClass 对象正在被销毁"); } }
|
语法要点:
- 析构函数名必须与类名相同
- 前面加上波浪号(~)
- 不能有访问修饰符、参数或返回值
- 每个类只能有一个析构函数
- 不能被直接调用,只能由垃圾回收器调用
析构函数的工作原理
编译器转换机制
当编译器遇到析构函数时,会自动将其转换为重写的 Finalize 方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| public class ResourceManager { ~ResourceManager() { ReleaseResources(); }
private void ReleaseResources() { Console.WriteLine("释放非托管资源"); } }
public class ResourceManager { protected override void Finalize() { try { ReleaseResources(); } finally { base.Finalize(); } } }
|
垃圾回收与终结队列
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| public class FinalizationDemo { private static int _instanceCount = 0; private readonly int _instanceId;
public FinalizationDemo() { _instanceId = ++_instanceCount; Console.WriteLine($"对象 {_instanceId} 已创建"); }
~FinalizationDemo() { Console.WriteLine($"对象 {_instanceId} 正在终结");
Thread.Sleep(100);
Console.WriteLine($"对象 {_instanceId} 终结完成"); } }
public class GCDemo { public static void DemonstrateFinalization() { Console.WriteLine("=== 垃圾回收与终结演示 ===");
for (int i = 0; i < 5; i++) { var obj = new FinalizationDemo(); }
Console.WriteLine("触发垃圾回收..."); GC.Collect(); GC.WaitForPendingFinalizers();
Console.WriteLine("垃圾回收完成"); } }
|
析构函数的作用与应用场景
非托管资源清理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| public class FileManager : IDisposable { private IntPtr _fileHandle; private bool _disposed = false;
public FileManager(string filePath) { _fileHandle = OpenFile(filePath); Console.WriteLine($"文件句柄已打开: {_fileHandle}"); }
~FileManager() { Console.WriteLine("析构函数被调用"); Dispose(false); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Console.WriteLine("清理托管资源"); }
if (_fileHandle != IntPtr.Zero) { CloseFile(_fileHandle); Console.WriteLine($"文件句柄已关闭: {_fileHandle}"); _fileHandle = IntPtr.Zero; }
_disposed = true; } }
private IntPtr OpenFile(string path) => new IntPtr(Random.Shared.Next(1000, 9999)); private void CloseFile(IntPtr handle) { } }
|
事件订阅清理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| public class EventPublisher { public event Action<string> MessageReceived;
public void PublishMessage(string message) { MessageReceived?.Invoke(message); } }
public class EventSubscriber { private readonly EventPublisher _publisher; private readonly string _name;
public EventSubscriber(EventPublisher publisher, string name) { _publisher = publisher; _name = name;
_publisher.MessageReceived += OnMessageReceived; Console.WriteLine($"订阅者 {_name} 已注册"); }
~EventSubscriber() { if (_publisher != null) { _publisher.MessageReceived -= OnMessageReceived; Console.WriteLine($"订阅者 {_name} 已取消订阅"); } }
private void OnMessageReceived(string message) { Console.WriteLine($"[{_name}] 收到消息: {message}"); } }
|
调试和监控
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public class ResourceTracker { private static readonly List<WeakReference> _trackedObjects = new(); private static readonly object _lock = new object();
private readonly string _objectType; private readonly DateTime _createdTime;
public ResourceTracker(string objectType) { _objectType = objectType; _createdTime = DateTime.Now;
lock (_lock) { _trackedObjects.Add(new WeakReference(this)); }
Console.WriteLine($"[跟踪] {_objectType} 对象已创建 - {_createdTime:HH:mm:ss.fff}"); }
~ResourceTracker() { var lifetime = DateTime.Now - _createdTime; Console.WriteLine($"[跟踪] {_objectType} 对象已销毁 - 生存时间: {lifetime.TotalMilliseconds:F0}ms");
LogObjectDestruction(_objectType, lifetime); }
private void LogObjectDestruction(string type, TimeSpan lifetime) { }
public static void PrintAliveObjects() { lock (_lock) { var aliveCount = _trackedObjects.Count(wr => wr.IsAlive); Console.WriteLine($"当前存活的跟踪对象数量: {aliveCount}"); } } }
|
高级应用:FinalizerHooker 实现
让我们深入分析您提供的 FinalizerHooker 代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| using System.Runtime.CompilerServices;
public static class FinalizerHooker<T> where T : class { private static readonly ConditionalWeakTable<T, Finalizer> _weak = new ConditionalWeakTable<T, Finalizer>();
public static void Hook(T instance, Action<T> action) { if (_weak.TryGetValue(instance, out var existedHookAction)) { existedHookAction.HookAction += action; } else { _weak.Add(instance, new Finalizer(instance, action)); } }
public static bool UnHook(T instance) { return _weak.Remove(instance); }
private class Finalizer { public Finalizer(T instance, Action<T> hookAction) { Instance = instance; HookAction = hookAction; }
~Finalizer() { try { HookAction?.Invoke(Instance); } catch (Exception ex) { Console.WriteLine($"FinalizerHooker 执行异常: {ex.Message}"); } }
public T Instance { get; } public Action<T> HookAction { get; set; } } }
public class FinalizerHookerDemo { public static void DemonstrateFinalizerHooker() { Console.WriteLine("=== FinalizerHooker 演示 ===");
var obj1 = new TestObject("Object1"); var obj2 = new TestObject("Object2");
FinalizerHooker<TestObject>.Hook(obj1, instance => { Console.WriteLine($"Hook回调: {instance.Name} 正在被销毁"); });
FinalizerHooker<TestObject>.Hook(obj2, instance => { Console.WriteLine($"Hook回调: {instance.Name} 的资源需要清理"); });
FinalizerHooker<TestObject>.Hook(obj1, instance => { Console.WriteLine($"第二个Hook: {instance.Name} 执行额外清理"); });
Console.WriteLine("对象创建完成,准备销毁...");
obj1 = null; obj2 = null;
GC.Collect(); GC.WaitForPendingFinalizers();
Console.WriteLine("FinalizerHooker 演示完成"); } }
public class TestObject { public string Name { get; }
public TestObject(string name) { Name = name; Console.WriteLine($"TestObject {Name} 已创建"); } }
|
重要注意事项
性能影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class PerformanceComparison { public static void ComparePerformance() { const int iterations = 1000000;
var sw1 = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { var obj = new ClassWithoutFinalizer(); } sw1.Stop();
var sw2 = Stopwatch.StartNew(); for (int i = 0; i < iterations; i++) { var obj = new ClassWithFinalizer(); } sw2.Stop();
Console.WriteLine($"无析构函数类创建时间: {sw1.ElapsedMilliseconds}ms"); Console.WriteLine($"有析构函数类创建时间: {sw2.ElapsedMilliseconds}ms"); Console.WriteLine($"性能差异: {((double)sw2.ElapsedMilliseconds / sw1.ElapsedMilliseconds - 1) * 100:F1}%"); } }
public class ClassWithoutFinalizer { public int Value { get; set; } }
public class ClassWithFinalizer { public int Value { get; set; }
~ClassWithFinalizer() { } }
|
异常处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| public class SafeFinalizerExample { private bool _disposed = false;
~SafeFinalizerExample() { try { RiskyCleanupOperation(); } catch (Exception ex) { LogException("析构函数异常", ex); } }
private void RiskyCleanupOperation() { if (Random.Shared.Next(10) == 0) { throw new InvalidOperationException("清理操作失败"); }
Console.WriteLine("清理操作成功"); }
private void LogException(string context, Exception ex) { Console.WriteLine($"[ERROR] {context}: {ex.Message}"); } }
|
与 IDisposable 的协作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class ProperResourceManagement : IDisposable { private FileStream _fileStream; private bool _disposed = false;
public ProperResourceManagement(string filePath) { _fileStream = new FileStream(filePath, FileMode.OpenOrCreate); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { _fileStream?.Dispose(); Console.WriteLine("托管资源已清理"); }
Console.WriteLine("非托管资源已清理");
_disposed = true; } }
~ProperResourceManagement() { Console.WriteLine("警告: 对象未正确Dispose,使用析构函数清理"); Dispose(false); } }
|
最佳实践建议
推荐做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| public class BestPracticeExample : IDisposable { private bool _disposed = false;
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing) { } _disposed = true; } }
~BestPracticeExample() { Dispose(false); }
protected void ThrowIfDisposed() { if (_disposed) { throw new ObjectDisposedException(GetType().Name); } } }
|
避免的做法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class BadPracticeExample { ~BadPracticeExample() { }
~BadPracticeExample() { }
~BadPracticeExample() { } }
|
实际应用示例
数据库连接管理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public class DatabaseConnection : IDisposable { private IDbConnection _connection; private bool _disposed = false;
public DatabaseConnection(string connectionString) { _connection = new SqlConnection(connectionString); _connection.Open(); Console.WriteLine("数据库连接已打开"); }
~DatabaseConnection() { Console.WriteLine("警告: 数据库连接未正确释放,使用析构函数清理"); Dispose(false); }
public void Dispose() { Dispose(true); GC.SuppressFinalize(this); }
protected virtual void Dispose(bool disposing) { if (!_disposed) { if (disposing && _connection != null) { if (_connection.State == ConnectionState.Open) { _connection.Close(); Console.WriteLine("数据库连接已正常关闭"); } _connection.Dispose(); } _disposed = true; } } }
|
总结
析构函数是 C#提供的重要资源管理机制,主要用于:
- 非托管资源清理 - 确保系统资源得到释放
- 备用清理机制 - 当开发者忘记调用 Dispose 时的保险措施
- 调试和监控 - 跟踪对象生命周期和资源使用情况
关键要点:
- 析构函数会影响 GC 性能,谨慎使用
- 总是配合 IDisposable 模式使用
- 使用 GC.SuppressFinalize 优化性能