簡體   English   中英

C#IDisposable問題

[英]C# IDisposable question

我有以下代碼示例:

public interface IRepository {
   // Whatever
}

public class SampleRepository : IRepository {
   // Implements 'Whatever'
}

public class NHibernateRepository : IRepository, IDisposable {

   // ...

   public void Dispose() { ... }
}

現在 - 真的很糟糕嗎? 我不確定,但這似乎與C++沒有標記虛擬基類的析構函數相同。

我不想讓IRepository接口實現IDisposable ,因為這會帶來不必要的復雜性和一堆類,這些類也必須實現IDisposable


該案件應如何處理?

我確信這可能發生在任何類型層次結構中 - 當派生類型之一必須管理可支配資源時。

那么我該怎么做 - 將IDisposable拉到第一個界面或保留它並希望用戶區分一次性和非一次性存儲庫?

謝謝。

是的,我會說這很糟糕 - 因為你不能以同樣的方式使用所有存儲庫。

我個人會使存儲庫接口擴展IDisposable - 畢竟,使用no-op實現它很容易。

這與主框架中StreamTextReaderTextWriter所做的選擇完全相同。 StringWriter (例如)不需要處理任何東西......但TextWriter仍然是一次性的。

所有這一切都是因為IDisposable在某些方面是一個奇怪的界面:它不傳達向呼叫者提供的東西......它傳達了呼叫者所需要的東西(或至少,強烈鼓勵可能的問題,如果你不'隨身攜帶)。

您可能遇到的唯一問題是使用某種類型的工廠,控制反轉或依賴注入模式/框架。 如果您想將對象用作接口,則永遠無法執行此操作:

IRepository repo = Factory.GetRepository();
repo.Dispose();

您可能想要引入一個實現IDisposable的INHibernateRepository。 因為IDisposable通常是如此低級別的操作,所以使接口實現此接口並不是一個大問題。

不,不要“拉掉IDisposable”。 保持接口原子,簡單和獨立。

除非您認為IDisposable是IRepository的基本特征(並且SampleRepository顯示它不是),否則它們之間不應該有任何推導。

這對我來說似乎完全沒問題。 有什么問題?

你所描述的是一個重要的附帶條件:一個類型的對象已經添加了“IDisposable”到它的基礎必須永遠不會傳遞給消費者,消費者可能最終持有或持續對象一段未知的時間。

基本上,IDisposable對象的所有者必須(*)要么處理對象本身,要么將對象交給可以接受並履行責任的新所有者。 最初,IDisposable對象通常由其創建者“擁有”,但是交接是常見的。 可以將IDispoable對象的引用賦予另一個對象而不轉移所有權; 在這種情況下,所有者仍然負責在不再需要時處置對象。 為此,所有者必須知道不再需要該對象。 最常見的模式是:

  1. 該對象作為參數傳遞給方法; 方法返回后,托管該方法的對象將不使用該對象。
  2. 該對象作為參數傳遞給一個方法,該方法將它存儲在某個對象的字段中,但該對象以后可能會以某種方式被請求銷毀該引用。
  3. 一次性作為參數傳遞給一個方法,該方法由一次性對象的所有者擁有所有引用的對象托管; 除非請求,托管對象將不使用一次性對象,並且一次性對象的所有者將知道它是否將永遠不再發出此類請求。

如果其中一種模式適用,您可能會處於良好狀態。 如果不是,你可能遇到麻煩。

首先,回答你的問題。 配置模式與C ++析構函數不同。 Dispose方法旨在處理類包含的資源,而不是處理類本身

將C ++析構函數標記為virtual的原因在.NET中不存在,因為引用類型的每個實例都有一個包含運行時類型信息的同步塊。 使用它,垃圾收集器可以適當地回收正確的內存量。

至於使用IDisposable擴展IRepository ,這將是一個快速修復,在絕大多數情況下是可以接受的。 我能看到的唯一反對意見是擴展接口將需要所有派生類來實現接口。 從表面上看,使用NOP(可能多次)實現接口似乎很容易,但您不應該這樣做。 但是,我可以提供另一種選擇。

相反,請考慮使用實現Dispose Pattern的抽象基類。 這將遵循處置模式的“標准”實現的結構。

public abstract class Repository : IDisposable  
{ 
    public void Dispose() { Dispose(true); }
    protected virtual Dispose(bool disposing) {  } 
}

public class NHibernateRepository : Repository { /* Impl here, add disposal. */ }

public class TestRepository : Repository { /* Impl with no resources */ }

請查看Microsoft編寫的Dispose Pattern Guidelines以查看更詳細的示例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM