对象实例化中的异常。初始化成员会发生什么?
问题描述:
根据this文章,字段在执行构造函数之前被初始化。但是,如果异常抛出构造函数呢?对象实例化将失败。对象实例化中的异常。初始化成员会发生什么?
但是,初始化字段会发生什么?他们仍然留在记忆里,还是立即收集垃圾?如果在构造函数中发生异常之前声明并初始化了非托管资源,该怎么办?这个非托管资源会存活吗?
答
如果在构造函数中引发异常,那么类型的集合没有区别,如果没有。 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#不会。
你用调试器试过了吗?这也有关系吗? – gunr2171 2014-10-07 20:49:10
没有尝试过使用调试器。当我们处理非托管资源时它很重要。 – Lucifer 2014-10-07 21:09:09