ãã®èšäºãããäžé£ã®èšäºå
šäœãå
¬éãå§ãããã®çµæã¯.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ã€ã®ãªãã·ã§ã³ãããããšãããããŸãã ããã«äºçŽããŠãã ããããããèµ·ãããªãçç±ïŒ
using(obj) { ... }
ã䜿çšãããšãå
éšã³ãŒããããã¯ã§äŸå€ãçºçããå¯èœæ§ããããŸããããã¯ã finally
ãããã¯ã§ãã£ãããããç§ãã¡ã«ã¯èŠããŸããïŒããã¯CïŒæ§æç³ã§ãïŒã ãã®ãããã¯ã§ã¯ãDisposeãæé»çã«åŒã³åºãããŸãã ãã ãããããçºçããªãå ŽåããããŸãã ããšãã°ã catch
ãŸãã¯finally
ãããã«ãcatch
ãããªãStackOverflowException
ã ããã¯åžžã«èæ
®ãããã¹ãã§ãã çµå±ãç¹å®ã®ã¹ã¬ãããååž°ç¶æ
ã«ãªããããæç¹ã§StackOverflowException
ããã£ããã£ãããŠè§£æŸãããªãã£ããªãœãŒã¹ã¯.NETã«ãã£ãŠå¿ããããŸãã çµå±ã®ãšããã圌ã¯ã¢ã³ãããŒãžãªãœãŒã¹ã解æŸããæ¹æ³ãããããŸãããOSããããã解æŸãããŸã§ïŒããšãã°ãããã°ã©ã ãçµäºãããšããã¢ããªã±ãŒã·ã§ã³ãçµäºããŠããç¡æéã«ïŒã¡ã¢ãªå
ã§ãã³ã°ããŸãã- å¥ã®DisposeïŒïŒããDisposeïŒïŒãåŒã³åºãå Žåã ãã®åŸãåã³ã圌ã«é£çµ¡ã§ããªãããšãèµ·ãããããããŸããã ãããŠãããã§ã®è³ªåã¯ãã¢ããªã±ãŒã·ã§ã³ã®äœè
ã®å¿ãã£ãœãã§ã¯ãããŸããã圌ãã¯ãDisposeïŒïŒãåŒã³åºãã®ãå¿ããŠãããšèšããŸãã ãã ãã®å ŽåããäŸå€ã¯äŸå€ã§ãã ãããä»ã§ã¯ãã¢ããªã±ãŒã·ã§ã³ãããŒãåæ¢ãããã®ã¯äŸå€ã ãã§ã¯ãããŸããã ããã§ã¯ãã¢ã«ãŽãªãºã ãå€éšDisposeïŒïŒã®åŒã³åºãã«å°éããªããšããäºå®ã«ã€ãªããäŸå€ã«ã€ããŠèª¬æããŠããŸãã
ãã®ãããªå Žåã¯ãã¹ãŠã管çãããŠããªããªãœãŒã¹ãå®ã«æµ®ããç¶æ
ã«ãªããŸãã çµå±ã®ãšãããã¬ããŒãžã³ã¬ã¯ã¿ãŒã¯ãåéããå¿
èŠããããšã¯èããŠããŸããã 圌ãè¡ãæ倧ã®ããš-次ã®ãã¹ã§ã圌ã¯
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(); }
ãã¡ã€ãã©ã€ãºããã»ã¹ã«é¢ããç¥èã䜿çšããŠäŸã匷åããããã«ãããäœããããŸããããã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(); }
ããã§ãã¢ã³ãããŒãžãªãœãŒã¹ãã«ãã»ã«åããåã®å®è£
äŸã¯å®å
šã«èŠããŸãã æ®å¿µãªããã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ãããã³ãããã®æŽŸçç©ãšããç¹å¥ãªã¿ã€ãã«ã€ããŠè©±ããŸãããã æåŸã«ãã¢ã³ãããŒãžãªãœãŒã¹ãžã®ã¢ã¯ã»ã¹ãæäŸããã¿ã€ãã®ãã³ãã¬ãŒããå®æãããŸãã ããããã®åã«ã管çãããŠããªãäžçãããéåžžãç§ãã¡ã«å±ããã¹ãŠã®ãã®ããªã¹ãããŠã¿ãŸãããã
- éåžžããããæ¥ãæåã§æãæåŸ
ããããã®ã¯ãã³ãã«ã§ãã .NETéçºè
ã«ãšã£ãŠãããã¯ç©ºã®èšèãããããŸãããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®äžçã®éåžžã«éèŠãªã³ã³ããŒãã³ãã§ãã ãã ããäžæ žãšãªããã³ãã«ã¯ããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ãšã®å¯Ÿè©±ã®ãªãŒãã³ã»ãã·ã§ã³ãå®çŸ©ãã32ããããŸãã¯64ãããã®æ°å€ã§ãã ã€ãŸããããšãã°ããã¡ã€ã«ãéããŠæäœããWinApié¢æ°ã®ä»£ããã«ãã³ãã«ãåãåããŸãã ãã®åŸãããã䜿çšããŠãæäœãç¶ããããšãã§ããŸãïŒdo * Seek *ã* Read *ã* Write *æäœã 2çªç®ã®äŸïŒãœã±ãããéããŠãããã¯ãŒã¯ãæäœããŸãã ç¹°ãè¿ãã«ãªããŸããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ããã³ãã«ãæäŸããŸãã .NETã®äžçã§ã¯ãèšè¿°åã¯* IntPtr *åã«æ ŒçŽãããŸãã
- 2çªç®ã¯ããŒã¿é
åã§ãã ã¢ã³ãããŒãžé
åãæäœããã«ã¯ãããã€ãã®æ¹æ³ããããŸããå®å
šã§ãªãã³ãŒãïŒå®å
šã§ãªãããŒã¯ãŒãïŒã䜿çšããããSafeBufferã䜿çšããŠããŒã¿ãããã¡ãŒã䟿å©ãª.NETã¯ã©ã¹ã«ã©ããããŸãã æåã®æ¹æ³ã¯ããé«éã§ããïŒããšãã°ããµã€ã¯ã«ã倧å¹
ã«æé©åã§ããŸãïŒã2çªç®ã®æ¹æ³ã¯ã¯ããã«å®å
šã§ãã çµå±ã®ãšããã圌ã¯ä»äºã®åºç€ãšããŠSafeHandleã䜿çšããŠããŸãã
- æååã æååã䜿çšãããšããã¹ãŠãããåçŽã«ãªããŸããããã¯ãååŸããæååã®åœ¢åŒãšãšã³ã³ãŒãã決å®ããããšãã¿ã¹ã¯ã ããã§ãã 次ã«ãæååãã³ããŒããïŒæååã¯ã©ã¹ã¯äžå€ã§ãïŒããã以äžäœãèããŸããã
- ã³ããŒã«ãã£ãŠååŸããããã®éåœã«ã€ããŠãŸã£ããèããå¿
èŠããªãValueTypeã
SafeHandleã¯ãCriticalFinalizerObjectãç¶æ¿ããç¹å¥ãª.NET CLRã¯ã©ã¹ã§ããããªãã¬ãŒãã£ã³ã°ã·ã¹ãã ã®ãã³ãã«ãã§ããã ãå®å
šãã€äŸ¿å©ã«ã©ããããããã«èšèšãããŠããŸãã
[SecurityCritical, SecurityPermission(SecurityAction.InheritanceDemand, UnmanagedCode=true)] public abstract class SafeHandle : CriticalFinalizerObject, IDisposable { protected IntPtr handle;
, 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);
? , 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();
_disposed
Dispose()
- . , :
- , . , . SyncBlockIndex, ( â ). ããªãã¡ , « » !
- memory traffic
- GC
, , . . ? ? 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) {
? . , , : - . , . . , . . *Disposable Design Principle*. , :
Disposing :
- Level 0
- ,
- :
- PrePrepareMethod,
- SecuritySafeCritical, ,
- ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success / MayFail)] CER
- , , « »
- Level 1
- Level 1 IDisposable
- Level 0 CriticalFinalizerObject
- Level 1 Level 0
- IDisposable.Dispose : Level 0, â Level 1
- ãªããªã â finalizer
- protected , Level 0 .
: . -.
ãŸãšã
é·æ
, . :
- : ,
- ,
- , (, - )
çæ
, :
- , , , , : , . , , . , , IDE ( , Dis⊠, ). Dispose , . , . :
IEnumerator<T>
IDisposable
? - , , IDisposable : IDisposable. «» , . , . , * -*, . Dispose() â . * *. â , ;
- , Dispose() . **. . , CheckDisposed() . , : « !»;
- ,
IDisposable
*explicit* . , IDisposable , . , . Dispose(), ; - . . GC . , , DisposableObject, ,
virtual void Dispose()
, , ; Dispose()
, tor
. disposing .- , , , â ** . , Dispose() . . , Lifetime.
- IDisposable . , , ;
- IDisposable . , , Garbage Collector;
- IDisposable Dispose() . : , IDisposable ;
- . ããªãã¡ , : , SafeHandle / CriticalHandle / CriticalFinalizerObject. Dispose(): .
- , . , Inversion of Control
Lifetime
, .