对象实例化中出现异常.初始化的成员会发生什么
本文关键字:成员 什么 初始化 实例化 异常 对象 | 更新日期: 2023-09-27 18:25:48
根据本文,字段在执行构造函数之前进行初始化。但是,如果在构造函数中抛出异常,该怎么办?对象实例化将失败。
但是初始化的字段会发生什么呢?它们是否仍保留在内存中,还是立即被垃圾收集?如果在构造函数中发生异常之前声明并初始化了非托管资源,该怎么办。此非托管资源能否生存?
如果在构造函数中抛出异常,则类型的集合与没有抛出异常时的集合没有什么不同。GC运行时,如果无法从根项访问对象,则会对其进行清理。如果由于对象初始化失败而没有引用该对象,则将在下一个集合中对其进行清理。
未管理的资源不会自行清理。这就是非托管资源的定义。无人管理的资源是指任何没有自行清理的资源;托管资源是自行清理的资源。在处理非托管资源时,您需要支持类型初始化失败的情况,并适当地清理资源,如果不这样做,则说明您泄露了这些资源,并且需要处理由此产生的任何后果。
如果一个对象的构造需要获取资源,那么在构造函数因任何原因抛出时,防止资源泄漏的唯一方法是要求使用工厂方法执行所有对象构造,该方法可以在出现问题时负责对象清理。不幸的是,.NET并没有做任何事情来提供方便。一种方法是:
static public MyThing Create(...)
{
var cleanupList = new List<IDisposable>();
try
{
MyThing Result = new MyThing(cleanupList, ...); // private or protected constructor
}
finally
{
if (Result == null)
{
List<Exception> failureList = null;
foreach (IDisposable cleaner in cleanupList)
{
try
{
cleaner.Dispose();
}
catch(Exception ex)
{
if (failureList == null)
failureList = new List<Exception>();
failureList.Add(ex);
}
}
if (failureList != null)
throw new FailedConstructorCleanupException(failureList);
}
}
}
如果在执行Dispose
操作时发生故障,FailedConstructorCleanupException
确实应该从抛出的构造函数封装异常,但当清理成功时,构造函数故障异常应该通过包装器,而不会被捕获和重新抛出。不幸的是,虽然VB.NET使Finally
块可以知道在Try
中抛出了什么异常,而不必捕获并重新抛出,但C#却不能。