对象实例化中出现异常.初始化的成员会发生什么

本文关键字:成员 什么 初始化 实例化 异常 对象 | 更新日期: 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#却不能。