根據this文章,字段在執行構造函數之前被初始化。但是,如果異常拋出構造函數呢?對象實例化將失敗。對象實例化中的異常。初始化成員會發生什麼?
但是,初始化字段會發生什麼?他們仍然留在記憶裏,還是立即收集垃圾?如果在構造函數中發生異常之前聲明並初始化了非託管資源,該怎麼辦?這個非託管資源會存活嗎?
根據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