.NET为未构造完成对象调用终结器的相关技术疑问
C#构造函数执行失败后终结器仍被调用的问题解答
1. 该行为是否符合规范?
完全符合C#语言规范。只要对象的内存已经在托管堆上完成分配,哪怕构造函数执行抛出异常、对象未完全初始化,CLR仍会将其视为可终结对象,最终调用它的终结器。
2. 微软官方文档中是否有该机制的相关说明?
有明确说明。官方文档提到:当对象构造过程中抛出异常时,CLR依然会触发终结器。这是因为对象内存已被分配,构造函数执行期间可能已经初始化了部分非托管资源,需要通过终结器完成清理,避免资源泄漏。
3. 该现象产生的原因是什么?
CLR创建对象的流程分为两步:
- 第一步:在托管堆上为对象分配内存,此时对象已经存在于堆中,拥有唯一的哈希标识;
- 第二步:调用构造函数完成对象的初始化。
如果构造函数执行失败抛出异常,对象的内存并未被回收——它已经是堆上的有效对象,只是未完成初始化。GC扫描托管堆时,会识别出带有终结器的对象(无论构造是否完成),将其加入终结队列,最终执行终结器以清理可能已分配的资源。
测试代码
using System; class TestFinalizer { public TestFinalizer() { Console.WriteLine($"构造函数执行中,对象哈希码:{GetHashCode()}"); // 模拟构造失败抛出异常 throw new InvalidOperationException("构造函数执行失败"); } ~TestFinalizer() { Console.WriteLine($"终结器被调用,对象哈希码:{GetHashCode()}"); } } class Program { static void Main() { try { new TestFinalizer(); } catch (Exception ex) { Console.WriteLine($"捕获异常:{ex.Message}"); } // 强制触发GC并等待终结器执行 GC.Collect(); GC.WaitForPendingFinalizers(); } }
运行输出
构造函数执行中,对象哈希码:7880838 捕获异常:构造函数执行失败 终结器被调用,对象哈希码:7880838
内容的提问来源于stack exchange,提问作者Timur Lemeshko
相关产品推荐
相关产品推荐

