廃棄デザインパターンの最もシンプルで信頼性の高い実装



このテンプレートは単純であるだけでなく、非常に単純であるように思われます。詳細は、複数の有名な本で説明されています。



それにもかかわらず、1つのプロジェクトのフレームワーク内であっても、自転車、松葉杖、漏れから動物園を作成するさまざまな方法で実装されることがよくあります。



自転車の発明を最小限に抑え、コードの量を最小限に抑え、表現力と透明性を高めることに基づいた実装方法を共有したいと思います。



前提条件



管理対象リソースと管理対象外リソースの混在なし



私は自分で実装したことはなく、同僚に管理されたリソースと管理されていないリソースの所有権を1つのクラスで使用することを勧めません。



したがって、1つのクラスは次のことができます。



実装の継承は望ましくない



どうしても必要な場合を除き、クラスの継承は使用しません;提案された実装では、シールクラスのインスタンスをリソースのオブジェクト所有者と想定しています。

これは、継承をサポートするために変更できないという意味ではありません。



Janitor.Fodyを使用して実装されたアンマネージリソースのラッパー



更新:この目的のために、 CriticalFinalizerObjectSafeHandleから継承されたクラスを使用する方が良いと、 コメントは正しく指摘しました



私が使用したもの
Fody用のこのプラグイン-コンパイル後にアセンブリコードを変更するための無料ツール-を使用すると、リソースの正しいリリースに必要な1,000の実装の詳細を手動で書き出すことができなくなります。

あなたのコード( ドキュメントの例):

public class Sample : IDisposable { IntPtr handle; public Sample() { handle = new IntPtr(); } public void Method() { //Some code } public void Dispose() { //must be empty } void DisposeUnmanaged() { CloseHandle(handle); handle = IntPtr.Zero; } [DllImport("kernel32.dll", SetLastError=true)] static extern bool CloseHandle(IntPtr hObject); }
      
      





後処理結果:

 public class Sample : IDisposable { IntPtr handle; volatile int disposeSignaled; bool disposed; public Sample() { handle = new IntPtr(); } void DisposeUnmanaged() { CloseHandle(handle); handle = IntPtr.Zero; } [DllImport("kernel32.dll", SetLastError = true)] static extern Boolean CloseHandle(IntPtr handle); public void Method() { ThrowIfDisposed(); //Some code } void ThrowIfDisposed() { if (disposed) { throw new ObjectDisposedException("TemplateClass"); } } public void Dispose() { if (Interlocked.Exchange(ref disposeSignaled, 1) != 0) { return; } DisposeUnmanaged(); GC.SuppressFinalize(this); disposed = true; } ~Sample() { Dispose(); } }
      
      







これで、この記事が書かれた最も一般的なケースに移ることができます。



管理対象リソースの破棄デザインパターンの実装



準備する



まず、 Reactive ExtensionsライブラリのCompositeDisposableクラスが必要です。

小さな拡張メソッドを追加する必要があります。

 public static void Add(this CompositeDisposable litetime, Action action) { lifetime.Add(Disposable.Create(action)); }
      
      





クリーンアップフィールドを追加する



 private readonly CompositeDisposable lifetime = new CompositeDisposable();
      
      





Disposeメソッドの実装



 public void Dispose() { lifetime.Dispose(); }
      
      





このメソッドにこれ以上何も追加する必要はありません。



明示的に構築されたリソースをクリアする



最も単純なコードをリソース割り当ての場所に直接追加するだけです。

それは:

 myOwnResourceField = new Resource(); //  -   if (myOwnResourceField != null) { myOwnResourceField.Dispose(); myOwnResourceField = null; }
      
      





次のようになりました:

 lifetime.Add(myOwnedResourceField = new Resource());
      
      







イベントの退会



それは:

 sender.Event += Handler; //  -   sender.Event -= Handler
      
      





次のようになりました:

 sender.Event += Handler; lifetime.Add(() => sender.Event -= Handler);
      
      







IObservableからのサブスクライブ解除



それは:

 subscription = observable.Subscribe(Handler); //  -   if (subscription != null) { subscription.Dispose(); subscription = null; }
      
      





次のようになりました:

 lifetime.Add(observable.Subscribe(Handler));
      
      







任意のクリーニングアクションの実行



 CreateAction(); lifetime.Add(() => DisposeAction());
      
      







オブジェクトの状態を確認する



 if (lifetime.IsDisposed)
      
      







結論



提案された方法:



記載された方法が読者に役立つなら、私はうれしいです。



All Articles