[DotNetBook] IDisposableの実装適切な䜿甚

この蚘事から、䞀連の蚘事党䜓を公開し始め、その結果は.NET CLRおよび.NET党般の䜜業に関する本になりたす。 IDisposableテヌマは、オヌバヌクロックペンサンプラヌずしお遞択されたした。 本党䜓がGitHub DotNetBookで利甚可胜になりたす。 だから問題ずプルリク゚ストは倧歓迎です:)

廃棄䜿い捚おデザむンの原則



さお、おそらく、.NETプラットフォヌムで開発するほずんどすべおのプログラマヌは、このパタヌンほど簡単なものはないず蚀うでしょう。 プラットフォヌムで䜿甚されおいる最も有名なテンプレヌトに぀いお知られおいるこず。 ただし、最も単玔で最も有名な問題領域であっおも、垞に2番目の底があり、その背埌には芋たこずのないいく぀かの隠れたポケットがありたす。 ただし、トピックを初めお芋おいる人ず他のすべおの人あなたがそれぞれの基本を芚えおいるようにこれらのパラグラフをスキップしないでください私は埓いたすの䞡方-最初から最埌たですべおを説明したす。

IDisposable



IDisposableずは䜕かを尋ねるず、おそらくそれが䜕であるかを答えるでしょう。

public interface IDisposable { void Dispose(); } 


むンタヌフェヌスは䜕のために䜜成されたしたか 結局のずころ、すべおのメモリをクリヌンアップするスマヌトガベヌゞコレクタヌがあり、メモリをクリヌンアップする方法さえ考えないようにするず、それをクリヌンアップする理由が完党には明らかになりたせん。 ただし、埮劙な違いがありたす。

ご泚意


Habréで公開されおいる章は曎新されおおらず、おそらくすでに叀いものです。 そのため、最新のテキストに぀いおは元に戻しおください。




管理されおいないリ゜ヌスを解攟するためにIDisposableが䜜成されおいるずいう誀解がありたす。 そしお、これは真実の䞀郚にすぎたせん。 これがそうでないこずをすぐに理解するには、アンマネヌゞリ゜ヌスの䟋を思い出すだけで十分です。 Fileクラスは管理されおいたせんか いや たぶんDbContext  繰り返したすが、いいえ。 アンマネヌゞリ゜ヌスは、.NETタむプシステムの䞀郚ではないものです。 プラットフォヌムによっお䜜成されたものではなく、その範囲を超えおいるもの。 簡単な䟋は、オペレヌティングシステムで開いおいるファむルハンドルです。 蚘述子は、オペレヌティングシステムによっお開かれたファむルを䞀意に識別する番号です。 あなたではなく、オペレヌティングシステムによっお。 すなわち すべおの制埡構造ファむルシステム䞊のファむルの座暙、フラグメンテヌションおよびその他のサヌビス情報の堎合のそのフラグメント、磁気HDDの堎合のシリンダヌ、ヘッド、セクタヌ番号などは、.NETプラットフォヌム内ではなく、OS内にありたす。 そしお、.NETプラットフォヌムに入る唯䞀のアンマネヌゞリ゜ヌスは、IntPtr番号です。 この番号はFileSafeHandleをラップし、FileSafeHandleはFileクラスでラップしたす。 すなわち Fileクラス自䜓はアンマネヌゞリ゜ヌスではありたせんが、远加のレむダヌオヌプンファむル蚘述子IntPtrを介しおアンマネヌゞリ゜ヌス自䜓を蓄積したす。 そのようなファむルからの読み取りはどうですか 䞀連のWinAPIたたはLinuxメ゜ッドを通じお。

アンマネヌゞリ゜ヌスの2番目の䟋は、マルチスレッドおよびマルチプロセスプログラムの同期プリミティブです。 ミュヌテックス、セマフォなど。 たたは、p / invokeを介しお枡されるデヌタ配列。

いいね 管理されおいないリ゜ヌスが敎理されたした。 これらの堎合にIDisposableを䜿甚する理由 次に、.NET Frameworkには、それが存圚しない堎合に䜕が起こるかに぀いおの考えがありたせん。 OS関数を䜿甚しおファむルを開くず、.NETはそれに぀いお䜕も知りたせん。 独自のニヌズに合わせおメモリを割り圓おた堎合たずえば、VirtualAllocを䜿甚、. NETはそれに぀いお䜕も認識したせん。 そしお、圌がこれに぀いお䜕も知らなければ、圌はVirtualAlloc呌び出しによっお占有されたメモリを解攟したせん。 たたは、OS API呌び出しを介しお盎接開かれたファむルを閉じたせん。 これの結果は完党に異なり、予枬䞍可胜です。 メモリを割り圓おすぎお解攟しない堎合たずえば、叀いメモリからポむンタをリセットするだけ、OSツヌルで開いたが閉じおいなかったファむルボヌル䞊のファむルを長時間ブロックする堎合、OutOfMemoryを取埗できたす。 。 ファむルボヌルを䜿甚した䟋は、アプリケヌションが閉じられた埌でもロックが保持されるため、特に優れおいたす。ファむルのオヌプン性は、ファむルが眮かれおいる偎によっお芏制されたす。 たた、リモヌト偎では、自分でファむルを閉じなかった堎合、ファむルを閉じる信号を受信したせん。

これらのすべおの堎合においお、型システムずプログラマヌの間で普遍的で認識可胜な「盞互䜜甚のプロトコル」が必芁であり、匷制閉鎖が必芁な型を䞀意に識別したす。 この_protocol_はIDisposableむンタヌフェむスです。 そしお、次のように聞こえたす型にIDisposableむンタヌフェむスの実装が含たれおいる堎合、そのむンスタンスの操䜜を終了した埌、 Dispose()呌び出す必芁がありたす。

そしおたさにこの理由のために、それを呌び出す2぀の暙準的な方法がありたす。 結局のずころ、原則ずしお、1぀のメ゜ッドのフレヌムワヌク内で、たたぱッセンスのむンスタンスの存続期間内に゚ンティティをすばやく操䜜するために、゚ンティティのむンスタンスを䜜成したす。

最初のオプションは、 using(...){ ... }おむンスタンスをラップするずきです。 すなわち usingブロックの最埌で、オブゞェクトを砎棄する必芁があるこずを明瀺的に瀺したす。 すなわち Dispose()ず呌ばれる必芁がありたす。 2番目のオプションは、オブゞェクトの存続期間の終了時に砎棄するこずです。これには、解攟する必芁があるオブゞェクトぞのリンクが含たれたす。 しかし、.NETでは、ファむナラむズメ゜ッドに加えお、オブゞェクトの自動砎棄を瀺唆するものは䜕もありたせん。 そうだね しかし、ファむナラむズは、呌び出されたずきに認識されないずいう理由で、私たちにはたったく適しおいたせん。 そしお、必芁なずきに解攟する必芁がありたす。たずえば、開いおいるファむルが䞍芁になった盎埌です。 そのため、IDisposableを自分で実装する必芁があり、Disposeメ゜ッドでも、所有しおいるすべおのナヌザヌに察しおDisposeを呌び出しお、それらを解攟する必芁がありたす。 したがっお、我々はプロトコルに準拠しおおり、これは非垞に重芁です。 結局、誰かが特定のプロトコルに準拠し始めた堎合、プロセスのすべおの参加者はそれを遵守しなければなりたせん。そうでなければ問題が発生したす。

IDisposableの実装バリ゚ヌション



IDisposableの実装から単玔なものから耇雑なものぞず進みたしょう。

頭に浮かぶこずができる最初で最も簡単な実装は、IDisposableを単に取埗しお実装するこずです。

 public class ResourceHolder : IDisposable { DisposableResource _anotherResource = new DisposableResource(); public void Dispose() { _anotherResource.Dispose(); } } 


すなわち 最初に、解攟する必芁があり、Disposeメ゜ッドで解攟されるリ゜ヌスのむンスタンスを䜜成したす。
ここに存圚せず、実装の䞀貫性を倱わせる唯䞀のものは、 Dispose()メ゜ッドによる砎棄埌にクラスむンスタンスをさらに凊理する可胜性です。

 public class ResourceHolder : IDisposable { private DisposableResource _anotherResource = new DisposableResource(); private bool _disposed; public void Dispose() { if(_disposed) return; _anotherResource.Dispose(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckDisposed() { if(_disposed) { throw new ObjectDisposedException(); } } } 


CheckDisposed()の呌び出しは、クラスのすべおのパブリックメ゜ッドの最初の匏で呌び出す必芁がありたす。 ただし、管理リ゜ヌス DisposableResource を砎棄するためにResourceHolderクラスの結果の構造が正垞に芋える堎合、管理されおいないリ゜ヌスをカプセル化する堎合はそうではありたせん。

管理されおいないリ゜ヌスオプションを考えおみたしょう。

 public class FileWrapper : IDisposable { IntPtr _handle; public FileWrapper(string name) { _handle = CreateFile(name, 0, 0, 0, 0, 0, IntPtr.Zero); } public void Dispose() { CloseHandle(_handle); } [DllImport("kernel32.dll", EntryPoint = "CreateFile", SetLastError = true)] private static extern IntPtr CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile); [DllImport("kernel32.dll", SetLastError=true)] private static extern bool CloseHandle(IntPtr hObject); } 


最埌の2぀の䟋の動䜜の違いは䜕ですか 最初のバヌゞョンでは、管理察象リ゜ヌスず別の管理察象リ゜ヌスずの盞互䜜甚に぀いお説明したす。 これは、プログラムが正垞に動䜜する堎合、リ゜ヌスはいずれの堎合でも解攟されるこずを意味したす。 結局のずころ、 DisposableResourceは管理されおいたす。぀たり、.NET CLRはそれに぀いおよく知っおおり、䞍正な動䜜の堎合は、メモリを解攟したす。 DisposableResource型がカプセル化するこずを意図的に仮定しおいないこずに泚意しおください。 任意のロゞックず構造がありたす。 管理察象リ゜ヌスず管理察象倖リ゜ヌスの䞡方を含めるこずができたす。 これは私たちを悩たせるべきではありたせん 。 ただし、他の人のラむブラリを逆コンパむルし、その人が䜿甚するタむプマネヌゞリ゜ヌスたたはアンマネヌゞリ゜ヌスを確認するよう求められるこずはありたせん。 そしお、タむプがアンマネヌゞリ゜ヌスを䜿甚する堎合、これを知る以倖にありたせん。 これはFileWrapperクラスで行いたす。 この堎合、どうなりたすか

管理されおいないリ゜ヌスを䜿甚する堎合、すべおが正垞でDisposeメ゜ッドが呌び出されたずきその埌はすべお正垞です:)、䜕かが発生しおDisposeメ゜ッドが機胜しなかったずきの2぀のオプションがあるこずがわかりたす。 すぐに予玄しおください。これが起こらない理由


このような堎合はすべお、管理されおいないリ゜ヌスが宙に浮いた状態になりたす。 結局のずころ、ガベヌゞコレクタヌは、収集する必芁があるずは考えおいたせん。 圌が行う最倧のこず-次のパスで、圌はFileWrapperタむプのオブゞェクトを含むオブゞェクトのグラフで最埌のリンクが倱われ、リンクがあるオブゞェクトによっおメモリが摩擊されるこずを理解したす。

これから身を守るには これらの堎合、オブゞェクトのファむナラむザヌを実装する必芁がありたす。 ファむナラむザに誀っおそのような名前が付けられるこずはありたせん。 これはデストラクタではありたせん。最初はCのファむナラむザずC ++のデストラクタの宣蚀が類䌌しおいるためず思われたす。 デストラクタずは異なり、ファむナラむザは*保蚌*ず呌ばれたすが、デストラクタは呌び出されない堎合がありたす Dispose()ように。 ファむナラむザは、ガベヌゞコレクションの起動時に呌び出されこれたでの知識で十分ですが、実際にはすべおが倚少耇雑です、 䜕か問題が発生した堎合にキャプチャされたリ゜ヌスのリリヌスを保蚌するこずを目的ずしおいたす。 たた、アンマネヌゞリ゜ヌスのリリヌスの堎合、ファむナラむザヌを実装する必芁がありたす。 たた、GCの開始時にファむナラむザヌが呌び出されるずいう事実のために、私は繰り返したすが、䞀般的な堎合、これがい぀起こるかわかりたせん。

コヌドを拡匵したしょう

 public class FileWrapper : IDisposable { IntPtr _handle; public FileWrapper(string name) { _handle = CreateFile(name, 0, 0, 0, 0, 0, IntPtr.Zero); } public void Dispose() { InternalDispose(); GC.SuppressFinalize(this); } private void InternalDispose() { CloseHandle(_handle); } ~FileWrapper() { InternalDispose(); } /// other methods } 


ファむナラむズプロセスに関する知識を䜿甚しお䟋を匷化し、それにより、䜕かがうたくいかず、Disposeが呌び出されない堎合にリ゜ヌスに関する情報が倱われないようにアプリケヌションを保護したした。 さらに、GC.SuppressFinalizeを呌び出しお、Disposeが呌び出された堎合に型むンスタンスのファむナラむズを無効にしたした。 同じリ゜ヌスを2回解攟する必芁はありたせんか これは、別の理由でも行う䟡倀がありたす。コヌドのランダムセクションを高速化するこずで、ファむナラむズキュヌから負担を取り陀きたす。これず䞊行しお、ファむナラむズがランダムに行われたす。

次に、䟋を匷化したしょう。

 public class FileWrapper : IDisposable { IntPtr _handle; bool _disposed; public FileWrapper(string name) { _handle = CreateFile(name, 0, 0, 0, 0, 0, IntPtr.Zero); } public void Dispose() { if(_disposed) return; _disposed = true; InternalDispose(); GC.SuppressFinalize(this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckDisposed() { if(_disposed) { throw new ObjectDisposedException(); } } private void InternalDispose() { CloseHandle(_handle); } ~FileWrapper() { InternalDispose(); } /// other methods } 


これで、アンマネヌゞリ゜ヌスをカプセル化する型の実装䟋は完党に芋えたす。 残念ながら、Repeated Dispose()はプラットフォヌムの事実䞊の暙準であり、呌び出すこずができたす。 倚くの堎合、呌び出しコヌドのトラブルを避けるために、 Dispose()繰り返し呌び出しを蚱可したすが、これは正しくありたせん。 ただし、MSドキュメントに目を向けるラむブラリのナヌザヌは、これを考慮せず、 Dispose()耇数の呌び出しを蚱可する堎合がありたす。 いずれにしおも、他のパブリックメ゜ッドを呌び出すず、オブゞェクトの敎合性が倱われたす。 オブゞェクトを砎棄するず、そのオブゞェクトを䜿甚できなくなりたす。 これは、各パブリックメ゜ッドの先頭にCheckDisposed呌び出しを挿入する必芁があるこずを意味したす。

ただし、このコヌドには非垞に深刻な問題があり、意図したずおりに動䜜したせん。 ガベヌゞコレクションプロセスがどのように機胜するかを思い出すず、詳现が1぀わかりたす。 ガベヌゞコレクションの堎合、GCはたず Objectから盎接継承されたすべおをファむナラむズし、その埌、 CriticalFinalizerObjectを実装するオブゞェクトに察しお取埗されたす。 しかし、蚭蚈した䞡方のクラスがObjectを継承しおいるこずがわかりたした。これは問題です。 「ラストマむル」に進む順序はわかりたせん。 ただし、より高いレベルのオブゞェクトは、ファむナラむザヌにアンマネヌゞリ゜ヌスを栌玍するオブゞェクトを操䜜しようずする堎合がありたすこれは既に悪い考えのように聞こえたすが。 ここで、ファむナラむズの順序は非垞に圹立ちたす。 そしお、蚭定するには、CriticalFinalizerObjectからアンマネヌゞリ゜ヌスをカプセル化する型を継承する必芁がありたす。

2番目の理由はより深いルヌツを持っおいたす。 メモリをあたり気にしないアプリケヌションの䜜成を蚱可したず想像しおください。 キャッシュなどのトリックなしで倧量に割り圓おたす。 そのようなアプリケヌションはOutOfMemoryExceptionで倱敗したす。 たた、アプリケヌションがこの䟋倖でクラッシュした堎合、コヌドの実行には特別な条件がありたす。䜕も割り圓おようずすべきではありたせん。 結局、前の䟋倖がキャッチされたずしおも、これは䟋倖の繰り返しに぀ながりたす。 これは、オブゞェクトの新しいむンスタンスを䜜成しおはならないずいう意味ではありたせん。 通垞のメ゜ッド呌び出しは、この䟋倖に぀ながる可胜性がありたす。 たずえば、ファむナラむズメ゜ッドを呌び出したす。 メ゜ッドは、初めお呌び出されたずきにコンパむルされるこずを思い出させおください。 そしお、これは通垞の動䜜です。 この問題から身を守るには 簡単です。 CriticalFinalizerObjectからオブゞェクトを継承する堎合、この型のすべおのメ゜ッドは、型がメモリにロヌドされるずすぐにコンパむルされたす。 それだけでなく、 [PrePrepareMethod]属性でメ゜ッドをマヌクするず、それらもプリコンパむルされ、十分なリ゜ヌスがない堎合は呌び出しの芳点から安党になりたす。

なぜこれがそんなに重芁なのですか 別の䞖界に向けお出発する人々になぜそんなに努力を費やすのですか そしお問題は、管理されおいないリ゜ヌスが非垞に長い時間システムにハングアップする可胜性があるこずです。 アプリケヌションが完了した埌でも。 コンピュヌタヌを再起動した埌でもナヌザヌがアプリケヌションでファむルボヌルを含むファむルを開いた堎合、そのファむルはリモヌトホストによっおブロックされ、タむムアりトによっお、たたはファむルを閉じおリ゜ヌスを解攟するず、解攟されたす。再起動埌でも、リモヌトホストがリリヌスするたで十分に長い時間埅぀必芁がありたす。 さらに、ファむナラむザで䟋倖をスロヌするこずを蚱可しないでください。これにより、CLRの死が加速し、アプリケヌションからの最終スロヌが発生したす。ファむナラむザぞの呌び出しはtry .. catchなりたせん。 すなわち リ゜ヌスを解攟するずき、リ゜ヌスをただ解攟できるこずを確認する必芁がありたす。 最埌になりたすが、CLRが緊急ドメむンのアンロヌドを実行する堎合、Objectから盎接継承するものずは異なり、CriticalFinalizerObjectから掟生した型のファむナラむザヌも呌び出されたす。

SafeHandle / CriticalHandle / SafeBuffer /デリバティブ



私は今あなたのためにPandoraの箱を開けるだろうず感じおいたす。 SafeHandle、CriticalHandle、およびそれらの掟生物ずいう特別なタむプに぀いお話したしょう。 最埌に、アンマネヌゞリ゜ヌスぞのアクセスを提䟛するタむプのテンプレヌトを完成させたす。 しかしその前に、管理されおいない䞖界から「通垞」私たちに届くすべおのものをリストしおみたしょう。



SafeHandleは、CriticalFinalizerObjectを継承する特別な.NET CLRクラスであり、オペレヌティングシステムのハンドルをできるだけ安党か぀䟿利にラップするように蚭蚈されおいたす。

 [SecurityCritical, SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] public abstract class SafeHandle : CriticalFinalizerObject, IDisposable { protected IntPtr handle; // ,    private int _state; //  (,  ) private bool _ownsHandle; //    handle.   ,     handle       private bool _fullyInitialized; //   [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] protected SafeHandle(IntPtr invalidHandleValue, bool ownsHandle) { } //     Dispose(false) [SecuritySafeCritical] ~SafeHandle() { Dispose(false); } //  hanlde    ,     p/invoke Marshal -  [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] protected void SetHandle(IntPtr handle) { this.handle = handle; } //    ,   IntPtr     .  //   ,    ,       //   .  ,      : // -        SetHandleasInvalid, DangerousGetHandle //       . // -        .     // ,       .       // IntPtr   ,             //      IntPtr [ResourceExposure(ResourceScope.None), ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public IntPtr DangerousGetHandle() { return handle; } //   (    ) public bool IsClosed { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get { return (_state & 1) == 1; } } //      .    ,  . public abstract bool IsInvalid { [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] get; } //     Close() [SecurityCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public void Close() { Dispose(true); } //     Dispose() [SecuritySafeCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] public void Dispose() { Dispose(true); } [SecurityCritical, ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] protected virtual void Dispose(bool disposing) { // ... } //       ,  ,  handle    . //     ,    [SecurityCritical, ResourceExposure(ResourceScope.None)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern void SetHandleAsInvalid(); //   ,  ,     // .       , ..   //    ,      . //   -     . //     = false,    // SafeHandleCriticalFailure,     SafeHandleCriticalFailure // Managed Debugger Assistant    . [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] protected abstract bool ReleaseHandle(); //    .      [SecurityCritical, ResourceExposure(ResourceScope.None)] [ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)] [MethodImplAttribute(MethodImplOptions.InternalCall)] public extern void DangerousAddRef(ref bool success); public extern void DangerousRelease(); } 


, SafeHandle, , .NET : . .., , SafeHandle , .. . , CLR. すなわち unsafe . : , SafeHandle, unsafe , , — . , unsafe , , ( , , ) , SafeHandle. : SafeHandle , . . : , .

— CriticalFinalizerObject , . SafeHandle-based SafeHandle-based , , ReleaseHandle — . , , . , .

, SafeHandlers:

 public class FileWrapper : IDisposable { SafeFileHandle _handle; bool _disposed; public FileWrapper(string name) { _handle = CreateFile(name, 0, 0, 0, 0, 0, IntPtr.Zero); } public void Dispose() { if(_disposed) return; _disposed = true; _handle.Dispose(); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckDisposed() { if(_disposed) { throw new ObjectDisposedException(); } } [DllImport("kernel32.dll", EntryPoint = "CreateFile", SetLastError = true)] private static extern SafeFileHandle CreateFile(String lpFileName, UInt32 dwDesiredAccess, UInt32 dwShareMode, IntPtr lpSecurityAttributes, UInt32 dwCreationDisposition, UInt32 dwFlagsAndAttributes, IntPtr hTemplateFile); /// other methods } 


? , DllImport SafeHandle-based , Marshal , 1, SafeFileHandle CreateFile. , ReadFile WriteFile (.. , — , handle ). , , . . , finalizer , . .

マルチスレッド


. IDisposable , Disposable , : . , — . — , . : . , . ,

 public class FileWrapper : IDisposable { IntPtr _handle; bool _disposed; object _disposingSync = new object(); public FileWrapper(string name) { _handle = CreateFile(name, 0, 0, 0, 0, 0, IntPtr.Zero); } public void Seek(int position) { lock(_disposingSync) { CheckDisposed(); // Seek API call } } public void Dispose() { lock(_disposingSync) { if(_disposed) return; _disposed = true; } InternalDispose(); GC.SuppressFinalize(this); } [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckDisposed() { lock(_disposingSync) { if(_disposed) { throw new ObjectDisposedException(); } } } private void InternalDispose() { CloseHandle(_handle); } ~FileWrapper() { InternalDispose(); } /// other methods } 


_disposed Dispose()

, , . . ? ? Dispose, ObjectDisposedException . : Dispose() . すなわち , FileWrapper . , .

Disposable Design Principle


IDisposable .NET ? , ? :

 public class Disposable : IDisposable { bool _disposed; public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } protected virtual void Dispose(bool disposing) { if(disposing) { //    } //    } protected void CheckDisposed() { if(_disposed) { throw new ObjectDisposedException(); } } ~Disposable() { Dispose(false); } } 


? . , , : - . , . . , . . *Disposable Design Principle*. , :

Disposing :


: . -.

たずめ


長所


, . :
  1. : ,
  2. ,
  3. , (, - )


短所


, :
  1. , , , , : , . , , . , , IDE ( , Dis
 , ). Dispose , . , . :
     IEnumerator<T> 
    IDisposable ?
  2. , , IDisposable : IDisposable. «» , . , . , * -*, . Dispose() — . * *. — , ;
  3. , Dispose() . **. . , CheckDisposed() . , : « !»;
  4. , IDisposable *explicit* . , IDisposable , . , . Dispose(), ;
  5. . . GC . , , DisposableObject, , virtual void Dispose() , , ;
  6. Dispose() , tor . disposing .
  7. , , , — ** . , Dispose() . . , Lifetime.



  1. IDisposable . , , ;
  2. IDisposable . , , Garbage Collector;
  3. IDisposable Dispose() . : , IDisposable ;
  4. . すなわち , : , SafeHandle / CriticalHandle / CriticalFinalizerObject. Dispose(): .
  5. , . , Inversion of Control Lifetime , .





Source: https://habr.com/ru/post/J341864/


All Articles