Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A Dispose metódus elsősorban a nem felügyelt erőforrások kiadására van implementálva. Amikor IDisposable implementációval rendelkező példánytagokkal dolgozunk, gyakori, hogy egymásra épülő Dispose hívásokat végzünk. A Disposemegvalósításának más okai is vannak, például a lefoglalt memória felszabadítása, a gyűjteményhez hozzáadott elemek eltávolítása vagy a beszerzett zárolás kiadásának jelzése.
A .NET-szemétgyűjtő nem foglal le és nem szabadít fel nem felügyelt memóriát. A megsemmisítési mintának nevezettobjektum eltávolításának mintája az objektum élettartamára vonatkozó sorrendet szabja meg. A felszabadítási minta a IDisposable interfészt implementáló objektumokhoz használatos. Ez a minta gyakori a fájl- és csőkezelők, a beállításjegyzék kezelői, a várakozási kezelők vagy a kezeletlen memória blokkjaira mutató mutatók használatakor, mivel a szemétgyűjtő nem tudja visszavenni a kezeletlen objektumokat.
Annak érdekében, hogy az erőforrások mindig megfelelően legyenek felszabadítva, egy Dispose metódusnak idempotensnek kell lennie, így többször is hívható, anélkül hogy kivételt okozna. Ezenkívül a Dispose későbbi meghívásainak nem kell semmit tennie.
A GC.KeepAlive metódushoz megadott példakód azt mutatja be, hogy a szemétgyűjtés hogyan okozhatja a véglegesítő futtatását, miközben az objektumra vagy annak tagjaira vonatkozó nem felügyelt hivatkozás még használatban van. Érdemes lehet GC.KeepAlive használni, hogy az objektum ne legyen jogosult a szemétgyűjtésre az aktuális rutin kezdetétől a metódus meghívásának pontig.
Borravaló
Függőséginjektálás esetén, amikor szolgáltatásokat regisztrálunk egy IServiceCollection-ben, a szolgáltatás élettartamának kezelése automatikusan történik az Ön helyett. A IServiceProvider és a hozzá tartozó IHost az erőforrás-törlést vezényli. A IDisposable és a IAsyncDisposable implementációi a megadott élettartamuk végén vannak megfelelően megsemmisítve.
További információ: Függőséginjektálás a .NET.
Kaszkádolt felszabadítási hívások
Ha az osztály rendelkezik egy IDisposable-t implementáló másik típus példányával, akkor az osztálynak magának is implementálnia kell a IDisposable-et. Általában egy osztály, amely példányosít egy IDisposable-implementációt, és példánytagként (vagy tulajdonságként) tárolja, szintén felelős a törlésért. Ez segít biztosítani, hogy a hivatkozott eldobható típusoknak lehetőségük legyen determinált módon tisztítást végezni a Dispose módszerrel. Az alábbi példában az osztály sealed
(vagy a Visual Basicben NotInheritable
).
using System;
public sealed class Foo : IDisposable
{
private readonly IDisposable _bar;
public Foo()
{
_bar = new Bar();
}
public void Dispose() => _bar.Dispose();
}
Public NotInheritable Class Foo
Implements IDisposable
Private ReadOnly _bar As IDisposable
Public Sub New()
_bar = New Bar()
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
_bar.Dispose()
End Sub
End Class
Borravaló
- Ha az osztálynak van egy IDisposable mezője vagy tulajdonsága, de nem saját, akkor az osztálynak nem kell implementálnia IDisposable. A IDisposable gyermekobjektumot létrehozó és tároló osztály általában szintén tulajdonos lesz, de bizonyos esetekben a tulajdonjog átkerülhet egy másik IDisposable típusba.
- Vannak olyan esetek, amikor
null
-ellenőrzést szeretne végezni egy véglegesítőben (ami magában foglalja a véglegesítő által hívottDispose(false)
metódust). Az egyik elsődleges ok az, ha nem biztos abban, hogy a példány teljesen inicializálva van-e (például kivétel dobódhat egy konstruktorban).
Dispose() és Dispose(bool)
A IDisposable interfészhez egyetlen paraméter nélküli metódus implementálása szükséges, Dispose. Emellett minden nem lezárt osztálynak Dispose(bool)
túlterhelési módszerrel kell rendelkeznie.
A metódus aláírások a következők:
-
public
nem virtuális (NotOverridable
Visual Basicben) (IDisposable.Dispose implementáció). -
protected virtual
(Overridable
a Visual Basicben)Dispose(bool)
.
A Dispose() metódus
Mivel a public
, nem virtuális (NotOverridable
a Visual Basicben) paraméter nélküli Dispose
metódust hívunk meg, amikor már nincs rá szükség (a típus felhasználója), a célja a nem felügyelt erőforrások felszabadítása, az általános tisztítás végrehajtása, valamint annak jelzése, hogy a véglegesítőnek , ha van ilyen, nem kell futtatnia. A felügyelt objektumhoz társított tényleges memória felszabadítása mindig a szemétgyűjtőtartománya. Emiatt szabványos implementációval rendelkezik:
public void Dispose()
{
// Dispose of unmanaged resources.
Dispose(true);
// Suppress finalization.
GC.SuppressFinalize(this);
}
Public Sub Dispose() _
Implements IDisposable.Dispose
' Dispose of unmanaged resources.
Dispose(True)
' Suppress finalization.
GC.SuppressFinalize(Me)
End Sub
A Dispose
metódus elvégzi az összes objektumkarbantartási feladatot, így a szemétgyűjtőnek többé nincs szüksége arra, hogy meghívja az objektumok Object.Finalize felülbírálását. Ezért a SuppressFinalize metódus hívása megakadályozza, hogy a szemétgyűjtő futtassa a véglegesítőt. Ha a típusnak nincs véglegesítője, a GC.SuppressFinalize hívásának nincs hatása. Az aktuális tisztítást a Dispose(bool)
metódus (overload) hajtja végre.
Az Dispose(bool) metódus túlterhelése
A túlterhelésnél a disposing
paraméter egy Boolean, amely azt jelzi, hogy a metódushívás egy Dispose metódusból (értéke true
) vagy egy döntőstől származik (értéke false
).
protected virtual void Dispose(bool disposing)
{
if (_disposed)
{
return;
}
if (disposing)
{
// Dispose managed state (managed objects).
// ...
}
// Free unmanaged resources.
// ...
_disposed = true;
}
Protected Overridable Sub Dispose(disposing As Boolean)
If disposed Then Exit Sub
If disposing Then
' Free managed resources.
' ...
End If
' Free unmanaged resources.
' ...
disposed = True
End Sub
Fontos
A disposing
paraméternek false
kell lennie, amikor egy finalizálóból hívják meg, és true
a IDisposable.Dispose metódusból való meghíváskor. Más szóval, akkor true
, ha determinisztikusan hívják, és false
, ha nemdeterminisztikusan hívják.
A metódus törzse három kódblokkból áll:
A feltételes visszatérés blokkja, ha az objektum már lebontásra került.
Egy feltételes blokk, amely felszabadítja a felügyelt erőforrásokat. Ez a blokk akkor fut, ha a
disposing
értéketrue
. Az általa felszabadított felügyelt erőforrások a következők lehetnek:- Felügyelt objektumok, amelyek IDisposableimplementálnak. A feltételes blokk a Dispose implementáció meghívására használható (kaszkádolt megsemmisítés). Ha egy System.Runtime.InteropServices.SafeHandle származtatott osztályt használt a nem felügyelt erőforrás burkolására, itt meg kell hívnia a SafeHandle.Dispose() implementációt.
- Olyan felügyelt objektumok, amelyek nagy mennyiségű memóriát használnak fel, vagy kevés erőforrást használnak fel. Nagy felügyelt objektumhivatkozásokat rendeljen
null
-hoz, hogy nagyobb valószínűséggel legyenek elérhetetlenebbek. Ez gyorsabban felszabadítja őket, mintha nemdeterminisztikus módon lettek volna visszanyerve.
Nem felügyelt erőforrásokat felszabadító blokk. Ez a blokk a
disposing
paraméter értékétől függetlenül fut.
Ha a metódushívás véglegesítőből származik, csak a nem felügyelt erőforrásokat felszabadító kódot kell végrehajtani. A implementátor feladata annak biztosítása, hogy a hamis elérési út ne működjön együtt az esetleg elvetett felügyelt objektumokkal. Ez azért fontos, mert az a sorrend, amelyben a szemétgyűjtő a véglegesítés során eltávolítja a felügyelt objektumokat, nem határozható meg.
Az eldobási minta implementálása
Minden nem lezárt osztályt (vagy nem NotInheritable
módosított Visual Basic osztályt) potenciális alaposztálynak kell tekinteni, mert örökölhetők. Ha implementálja az elidegenítési mintát bármely lehetséges alaposztályhoz, a következő metódusokat kell hozzáadnia az osztályhoz:
- Egy Dispose implementáció, amely meghívja a
Dispose(bool)
metódust. - Egy
Dispose(bool)
metódus, amely elvégzi a tényleges törlést. - Ha az osztály kezeletlen erőforrásokkal foglalkozik, vagy biztosítson felülbírálást a Object.Finalize metódushoz, vagy csomagolja be a kezeletlen erőforrást egy SafeHandle-be.
Fontos
Véglegesítőre (Object.Finalize felülbírálásra) csak akkor van szükség, ha közvetlenül felügyelet nélküli erőforrásokra hivatkozik. Ez egy rendkívül fejlett forgatókönyv, amely általában elkerülhető:
- Ha az osztály csak felügyelt objektumokrahivatkozik, az osztály továbbra is megvalósíthatja a megsemmisítési mintát. Nincs szükség véglegesítő implementálására.
- Ha felügyelet nélküli erőforrásokkalkell foglalkoznia, erősen javasoljuk, hogy a felügyelet nélküli IntPtr leírót csomagolja be egy SafeHandle. A SafeHandle véglegesítőt biztosít, hogy ne kelljen saját magának írnia egyet. További információért lásd a Biztonságos fogantyúk bekezdést.
Alaposztály felügyelt erőforrásokkal
Íme egy általános példa egy olyan alaposztály elidegenítési mintájának implementálására, amely csak felügyelt erőforrásokat birtokol.
using System;
using System.IO;
public class DisposableBase : IDisposable
{
// Detect redundant Dispose() calls.
private bool _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
_isDisposed = true;
if (disposing)
{
// Dispose managed state.
_managedResource?.Dispose();
_managedResource = null;
}
}
}
}
Imports System.IO
Public Class DisposableBase
Implements IDisposable
' Detect redundant Dispose() calls.
Private _isDisposed As Boolean
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True
If disposing Then
' Dispose managed state.
_managedResource?.Dispose()
_managedResource = Nothing
End If
End If
End Sub
End Class
Jegyzet
Az előző példa egy próbabábuMemoryStream objektumot használ a minta szemléltetésére. Ehelyett bármilyen IDisposable használható.
Alaposztály nem felügyelt erőforrásokkal
Íme egy példa egy alaposztály kiürítési mintájának implementálására, amely felülbírálja a Object.Finalize-t annak érdekében, hogy megtisztítsa a nem felügyelt erőforrásokat, amelyekkel rendelkezik. A példa azt is bemutatja, hogyan implementálhat Dispose(bool)
szálbiztos módon. A szinkronizálás kritikus fontosságú lehet a többszálas alkalmazások nem felügyelt erőforrásainak kezelésekor. Ahogy korábban említettük, ez egy speciális forgatókönyv.
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Threading;
public class DisposableBaseWithFinalizer : IDisposable
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// A pointer to 10 bytes allocated on the unmanaged heap.
private IntPtr _unmanagedResource = Marshal.AllocHGlobal(10);
~DisposableBaseWithFinalizer() => Dispose(false);
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
if (disposing)
{
_managedResource?.Dispose();
_managedResource = null;
}
Marshal.FreeHGlobal(_unmanagedResource);
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports System.Threading
Public Class DisposableBaseWithFinalizer
Implements IDisposable
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed == 0 means Dispose(bool) has not been called yet.
' _isDisposed == 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' A pointer to 10 bytes allocated on the unmanaged heap.
Private _unmanagedResource As IntPtr = Marshal.AllocHGlobal(10)
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 Then
If disposing Then
_managedResource?.Dispose()
_managedResource = Nothing
End If
Marshal.FreeHGlobal(_unmanagedResource)
End If
End Sub
End Class
Jegyzet
- Az előző példa a AllocHGlobal használatával foglal le 10 bájtot a konstruktorban lévő nem felügyelt halomban, és felszabadítja a puffert a
Dispose(bool)
-ben a FreeHGlobalmeghívásával. Ez egy illusztrációs célú próba-hozzárendelés. - Ismét javasoljuk, hogy kerülje a véglegesítő implementálását. Lásd: Az eldobási minta implementálása egyéni biztonságos kezelővel az előző példának megfelelően, amely a nem determinisztikus véglegesítést és szinkronizálást SafeHandle-nek delegálja.
Borravaló
A C#-ban a véglegesítést a véglegesítőmegadásával valósítja meg, nem pedig a Object.Finalizefelülírásával. A Visual Basicben létrehozhat egy véglegesítőt Protected Overrides Sub Finalize()
.
A származtatott osztály eltávolítási mintájának implementálása
A IDisposable interfészt megvalósító osztályból származó osztály nem implementálható IDisposable, mert a IDisposable.Dispose alaposztály-implementációját a származtatott osztályok öröklik. Ehelyett egy származtatott osztály törléséhez a következőket kell megadnia:
- Egy
protected override void Dispose(bool)
metódus, amely felülbírálja az alaposztály metódusát, és elvégzi a származtatott osztály tényleges törlését. Ennek a metódusnak argumentumként meg kell hívnia abase.Dispose(bool)
(MyBase.Dispose(bool)
a Visual Basicben) metódust is, amely argumentumként adja át a dekontribúciós állapotot (bool disposing
paramétert). - Vagy egy SafeHandle osztályból származtatott osztály, amely a nem felügyelt erőforrást burkolja (ajánlott), vagy a Object.Finalize metódus felülbírálása. A SafeHandle osztály biztosít egy véglegesítőt, amely megszabadít attól, hogy saját magadnak kelljen megírnod egyet. Ha véglegesítő függvényt ad meg, a
Dispose(bool)
túlterhelést kell meghívniafalse
argumentummal.
Íme egy példa a biztonságos fogantyút használó származtatott osztály felszabadítási mintájának megvalósítására szolgáló általános sablonra:
using System.IO;
public class DisposableDerived : DisposableBase
{
// To detect redundant calls
private bool _isDisposed;
// Instantiate a disposable object owned by this class.
private Stream? _managedResource = new MemoryStream();
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
_isDisposed = true;
if (disposing)
{
_managedResource?.Dispose();
_managedResource = null;
}
}
// Call base class implementation.
base.Dispose(disposing);
}
}
Imports System.IO
Public Class DisposableDerived
Inherits DisposableBase
' To detect redundant calls
Private _isDisposed As Boolean
' Instantiate a disposable object owned by this class.
Private _managedResource As Stream = New MemoryStream()
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True
If disposing Then
_managedResource?.Dispose()
_managedResource = Nothing
End If
End If
' Call base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
Jegyzet
Az előző példa egy SafeFileHandle objektummal szemlélteti a mintát; bármely SafeHandle-ből származó objektum is használható. Vegye figyelembe, hogy a példa nem hozza létre megfelelően a SafeFileHandle objektumot.
Itt van az általános minta a dispose minta implementálásához egy olyan származtatott osztályban, amely felülírja a Object.Finalize-t.
using System.Threading;
public class DisposableDerivedWithFinalizer : DisposableBaseWithFinalizer
{
// Detect redundant Dispose() calls in a thread-safe manner.
// _isDisposed == 0 means Dispose(bool) has not been called yet.
// _isDisposed == 1 means Dispose(bool) has been already called.
private int _isDisposed;
~DisposableDerivedWithFinalizer() => Dispose(false);
// Protected implementation of Dispose pattern.
protected override void Dispose(bool disposing)
{
// In case _isDisposed is 0, atomically set it to 1.
// Enter the branch only if the original value is 0.
if (Interlocked.CompareExchange(ref _isDisposed, 1, 0) == 0)
{
if (disposing)
{
// TODO: dispose managed state (managed objects).
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
}
// Call the base class implementation.
base.Dispose(disposing);
}
}
Imports System.Threading
Public Class DisposableDerivedWithFinalizer
Inherits DisposableBaseWithFinalizer
' Detect redundant Dispose() calls in a thread-safe manner.
' _isDisposed == 0 means Dispose(bool) has not been called yet.
' _isDisposed == 1 means Dispose(bool) has been already called.
Private _isDisposed As Integer
Protected Overrides Sub Finalize()
Dispose(False)
End Sub
' Protected implementation of Dispose pattern.
Protected Overrides Sub Dispose(disposing As Boolean)
' In case _isDisposed is 0, atomically set it to 1.
' Enter the branch only if the original value is 0.
If Interlocked.CompareExchange(_isDisposed, 1, 0) = 0 Then
If disposing Then
' TODO: dispose managed state (managed objects).
End If
' TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
' TODO: set large fields to null.
End If
' Call the base class implementation.
MyBase.Dispose(disposing)
End Sub
End Class
Biztonságos fogópontok
Az objektum véglegesítőjének kódjának írása összetett feladat, amely problémákat okozhat, ha nem megfelelően történik. Ezért azt javasoljuk, hogy véglegesítő helyett System.Runtime.InteropServices.SafeHandle objektumokat hozzon létre.
A System.Runtime.InteropServices.SafeHandle egy absztrakt felügyelt típus, amely egy nem felügyelt erőforrást azonosító System.IntPtr-et becsomagol. Windows rendszeren azonosíthat egy kezelőt, Unix rendszeren pedig egy fájlleírót. A SafeHandle
biztosítja az erőforrás egyszeri és egyszeri kiadásának biztosításához szükséges összes logikát, akár a SafeHandle
eltávolításakor, akár a SafeHandle
összes hivatkozásának elvetésekor, illetve a SafeHandle
példány véglegesítésekor.
A System.Runtime.InteropServices.SafeHandle egy absztrakt alaposztály. A származtatott osztályok különféle típusú kezelők számára biztosítanak meghatározott példányokat. Ezek a származtatott osztályok ellenőrzik, hogy a System.IntPtr mely értékei tekinthetők érvénytelennek, és hogyan szabadítható fel ténylegesen a fogantyú. A SafeFileHandle például a SafeHandle
alapján becsomagolja a nyitott fájlleírókat azonosító IntPtrs
, és felülírja annak SafeHandle.ReleaseHandle() metódusát a bezáráshoz (Unix esetén a close
függvényen, Windows esetén a CloseHandle
függvényen keresztül). A .NET-kódtárakban lévő API-k többsége, amelyek nem felügyelt erőforrást hoznak létre, becsomagolják azt egy SafeHandle
-ba, és szükség szerint visszaadják Önnek a SafeHandle
-et, a nyers mutató átadása helyett. Olyan helyzetekben, amikor egy nem felügyelt összetevővel lép kapcsolatba és kap egy nem felügyelt erőforrást IntPtr
azonosítóval, létrehozhat egy saját SafeHandle
típust a burkoláshoz. Ennek eredményeképpen kevés nemSafeHandle
típusnak kell véglegesítőket implementálnia. A legtöbb eldobható minta implementáció csak más felügyelt erőforrások burkolását végzi, amelyek némelyike SafeHandle
objektum lehet.
Az eldobási minta implementálása egyedi biztonságos fogantyúval
Az alábbi kód bemutatja, hogyan kezelhetők a nem felügyelt erőforrások egy SafeHandleimplementálásával.
using System;
using System.IO;
using System.Runtime.InteropServices;
using Microsoft.Win32.SafeHandles;
// Wraps the IntPtr allocated by Marshal.AllocHGlobal() into a SafeHandle.
class LocalAllocHandle : SafeHandleZeroOrMinusOneIsInvalid
{
private LocalAllocHandle() : base(ownsHandle: true) { }
// No need to implement a finalizer - SafeHandle's finalizer will call ReleaseHandle for you.
protected override bool ReleaseHandle()
{
Marshal.FreeHGlobal(handle);
return true;
}
// Allocate bytes with Marshal.AllocHGlobal() and wrap the result into a SafeHandle.
public static LocalAllocHandle Allocate(int numberOfBytes)
{
IntPtr nativeHandle = Marshal.AllocHGlobal(numberOfBytes);
LocalAllocHandle safeHandle = new LocalAllocHandle();
safeHandle.SetHandle(nativeHandle);
return safeHandle;
}
}
public class DisposableBaseWithSafeHandle : IDisposable
{
// Detect redundant Dispose() calls.
private bool _isDisposed;
// Managed disposable objects owned by this class
private LocalAllocHandle? _safeHandle = LocalAllocHandle.Allocate(10);
private Stream? _otherUnmanagedResource = new MemoryStream();
// Public implementation of Dispose pattern callable by consumers.
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
// Protected implementation of Dispose pattern.
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
_isDisposed = true;
if (disposing)
{
// Dispose managed state.
_otherUnmanagedResource?.Dispose();
_safeHandle?.Dispose();
_otherUnmanagedResource = null;
_safeHandle = null;
}
}
}
}
Imports System
Imports System.IO
Imports System.Runtime.InteropServices
Imports Microsoft.Win32.SafeHandles
' Wraps the IntPtr allocated by Marshal.AllocHGlobal() into a SafeHandle.
Public Class LocalAllocHandle
Inherits SafeHandleZeroOrMinusOneIsInvalid
Private Sub New()
MyBase.New(True)
End Sub
' No need to implement a finalizer - SafeHandle's finalizer will call ReleaseHandle for you.
Protected Overrides Function ReleaseHandle() As Boolean
Marshal.FreeHGlobal(handle)
Return True
End Function
' Allocate bytes with Marshal.AllocHGlobal() and wrap the result into a SafeHandle.
Public Shared Function Allocate(numberOfBytes As Integer) As LocalAllocHandle
Dim nativeHandle As IntPtr = Marshal.AllocHGlobal(numberOfBytes)
Dim safeHandle As New LocalAllocHandle()
safeHandle.SetHandle(nativeHandle)
Return safeHandle
End Function
End Class
Public Class DisposableBaseWithSafeHandle
Implements IDisposable
' Detect redundant Dispose() calls.
Private _isDisposed As Boolean
' Managed disposable objects owned by this class
Private _safeHandle As LocalAllocHandle = LocalAllocHandle.Allocate(10)
Private _otherUnmanagedResource As Stream = New MemoryStream()
' Public implementation of Dispose pattern callable by consumers.
Public Sub Dispose() Implements IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
' Protected implementation of Dispose pattern.
Protected Overridable Sub Dispose(disposing As Boolean)
If Not _isDisposed Then
_isDisposed = True
If disposing Then
' Dispose managed state.
_otherUnmanagedResource?.Dispose()
_safeHandle?.Dispose()
_otherUnmanagedResource = Nothing
_safeHandle = Nothing
End If
End If
End Sub
End Class
Jegyzet
A DisposableBaseWithSafeHandle
osztály viselkedése egyenértékű a DisposableBaseWithFinalizer
osztály viselkedésével egy korábbi példában, de az itt bemutatott megközelítés biztonságosabb:
- Nincs szükség véglegesítő implementálására, mert SafeHandle gondoskodik a véglegesítésről.
- A szálbiztonság biztosításához nincs szükség szinkronizálásra. Annak ellenére, hogy versenyfeltétel áll fenn a
DisposableBaseWithSafeHandle
Dispose
megvalósításában, SafeHandle garantálja, hogy SafeHandle.ReleaseHandle csak egyszer lesz meghívva.
Beépített biztonságos fogópontok a .NET-ben
A Microsoft.Win32.SafeHandles névtér következő származtatott osztályok biztonságos fogantyúkat biztosítanak.
Osztály | Az általa birtokolt erőforrások |
---|---|
SafeFileHandle SafeMemoryMappedFileHandle SafePipeHandle |
Fájlok, memórialeképezett fájlok és csövek |
SafeMemoryMappedViewHandle | Memórianézetek |
SafeNCryptKeyHandle SafeNCryptProviderHandle SafeNCryptSecretHandle |
Titkosítási szerkezetek |
SafeRegistryHandle | Rendszerleíró kulcsok |
SafeWaitHandle | Várakozási fogópontok |