Dispose メソッドは、主にアンマネージ リソースを解放するために実装されます。 実装 IDisposable インスタンス メンバーを操作する場合、Dispose 呼び出しを連鎖させるのが一般的です。 Disposeを実装する理由は他にもあります。たとえば、割り当てられたメモリの解放、コレクションに追加された項目の削除、取得されたロックの解放の通知などです。
.NET ガベージ コレクター は、アンマネージ メモリの割り当てや解放を行いません。 破棄パターンと呼ばれるオブジェクトを破棄する パターンでは、オブジェクトの有効期間に順序が適用されます。 dispose パターンは、IDisposable インターフェイスを実装するオブジェクトに使用されます。 このパターンは、ガベージ コレクターがアンマネージ オブジェクトを再利用できないため、ファイル ハンドルとパイプ ハンドル、レジストリ ハンドル、待機ハンドル、またはアンマネージ メモリのブロックへのポインターを操作する場合に一般的です。
リソースが常に適切にクリーン アップされるようにするには、 Dispose メソッドをべき等にして、例外をスローすることなく複数回呼び出されるようにする必要があります。 さらに、以降の Dispose の呼び出しでは何も実行されないはずです。
GC.KeepAlive メソッドに示されたコード例は、管理外参照がオブジェクトやそのメンバーに対してまだ使用されている間に、ガベージコレクションがファイナライザーを実行する動作を示しています。 GC.KeepAlive を利用して、現在のルーチンの先頭からこのメソッドが呼び出された時点まで、オブジェクトをガベージ コレクションに使用できないようにすることが理にかなっている場合があります。
ヒント
依存関係の挿入に関しては、IServiceCollectionにサービスを登録する場合、サービスの有効期間 は、ユーザーに代わって暗黙的に管理されます。 IServiceProvider とそれに対応する IHost は、リソースのクリーンアップを調整します。 具体的には、IDisposable と IAsyncDisposable の実装は、指定された有効期間の終了時に適切に破棄されます。
詳細については、「.NET での依存関係の挿入」を参照してください。
カスケード破棄呼び出し
クラスが IDisposableを実装する別の型のインスタンスを所有している場合は、包含クラス自体も IDisposable実装する必要があります。 通常、 IDisposable 実装をインスタンス化し、インスタンス メンバー (またはプロパティ) として格納するクラスも、そのクリーンアップを担当します。 これにより、参照先の破棄可能な型に、Dispose メソッドを使用してクリーンアップを確定的に実行する機会が与えられるのに役立ちます。 次の例では、クラスは sealed (または Visual Basic では 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
ヒント
- クラスに IDisposable フィールドまたはプロパティがあり、それを 所有 していない場合、クラスは IDisposableを実装する必要はありません。 通常、 IDisposable 子オブジェクトを作成して格納するクラスも所有者になりますが、場合によっては所有権を別の IDisposable 型に転送できます。
- ファイナライザー (ファイナライザーによって呼び出された
nullメソッドを含む) でDispose(false)チェックを実行する必要がある場合があります。 主な理由の一つは、インスタンスが完全に初期化されたかどうか確信が持てない場合です(たとえば、コンストラクターで例外が発生する可能性があります)。
Dispose() と Dispose(bool)
IDisposable インターフェイスには、パラメーターなしの単一のメソッド (Dispose) の実装が必要です。 また、シールされていないクラスには、Dispose(bool) オーバーロード メソッドが必要です。
メソッドシグネチャは次のとおりです。
-
public非仮想 (Visual Basic でNotOverridable) (IDisposable.Dispose の実装)。 -
protected virtual(Visual Basic のOverridable)Dispose(bool)。
Dispose() メソッド
public、非仮想 (Visual Basic ではNotOverridable)、パラメーターなしの Dispose メソッドは(型のコンシューマーによって) 不要になったときに呼び出されるため、その目的は、アンマネージ リソースを解放し、一般的なクリーンアップを実行し、ファイナライザーが存在する場合は実行する必要がないことを示します。 マネージド オブジェクトに関連付けられている実際のメモリの解放は、常に ガベージ コレクターのドメインです。 このため、標準の実装があります。
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
Dispose メソッドはすべてのオブジェクトクリーンアップを実行するため、ガベージ コレクターはオブジェクトの Object.Finalize オーバーライドを呼び出す必要がなくなりました。 そのため、SuppressFinalize メソッドを呼び出すと、ガベージ コレクターがファイナライザーを実行できなくなります。 型にファイナライザーがない場合、GC.SuppressFinalize の呼び出しは無効です。 実際のクリーンアップは、Dispose(bool) メソッドのオーバーロードによって実行されます。
Dispose(bool) メソッドのオーバーロード
オーバーロードでは、disposing パラメーターは、メソッドの呼び出しが Boolean メソッド (その値が Dispose) またはファイナライザー (その値が true) から取得されるかどうかを示す 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
重要
disposing パラメーターは、ファイナライザーから呼び出されたときに false し、true メソッドから呼び出されたときに IDisposable.Dispose する必要があります。 つまり、決定論的に呼び出されたときに true され、非決定的に呼び出されたときに false されます。
メソッドの本体は、次の 3 つのコード ブロックで構成されます。
オブジェクトが既に破棄されている場合のための条件付きの戻り値ブロック。
マネージド リソースを解放する条件付きブロック。 このブロックは、
disposingの値がtrue場合に実行されます。 解放されるマネージド リソースには、次のものが含まれます。- IDisposableを実装するマネージド オブジェクト。 条件付きブロックを使用して Dispose の実装を呼び出すことができます (カスケード破棄)。 System.Runtime.InteropServices.SafeHandle の派生クラスを使用してアンマネージ リソースをラップした場合は、ここで SafeHandle.Dispose() 実装を呼び出す必要があります。
- 大量のメモリを消費したり、不足しているリソースを消費したりするマネージド オブジェクト。
nullに大きなマネージド オブジェクト参照を割り当てて、到達不能になる可能性を高めます。 これにより、非決定的に回収された場合よりも速く解放されます。
管理されていないリソースを解放するブロック。 このブロックは、
disposingパラメーターの値に関係なく実行されます。
メソッド呼び出しがファイナライザーから来ている場合は、アンマネージ リソースを解放するコードのみを実行する必要があります。 実装者には、誤ったパスが破棄された可能性のあるマネージドオブジェクトと干渉しないよう確認する責任があります。 これは重要です。終了時にガベージ コレクターがマネージド オブジェクトを破棄する順序は非決定的であるためです。
"このディスポーズパターンを実装する"
非シール クラス (または NotInheritableとして変更されていない Visual Basic クラス) はすべて、継承される可能性があるため、基底クラスと見なす必要があります。 基底クラスの可能性がある場合に dispose パターンを実装する場合は、クラスに次のメソッドを追加する必要があります。
-
Dispose メソッドを呼び出す
Dispose(bool)実装。 - 実際のクリーンアップを実行する
Dispose(bool)メソッド。 - クラスがアンマネージ リソースを処理する場合は、 Object.Finalize メソッドにオーバーライドを指定するか、アンマネージ リソースを SafeHandleでラップします。
重要
ファイナライザー ( Object.Finalize オーバーライド) は、アンマネージ リソースを直接参照する場合にのみ必要です。 これは、通常回避できる高度なシナリオです。
- クラスがマネージド オブジェクトのみを参照している場合でも、クラスで dispose パターンを実装できます。 ファイナライザーを実装する必要はありません。
- アンマネージ リソースを処理する必要がある場合は、アンマネージ IntPtr ハンドルを SafeHandleにラップすることを強くお勧めします。 SafeHandleはファイナライザーを提供するので、自分でファイナライザーを記述する必要はありません。 詳細については、 セーフ ハンドル の段落を参照してください。
マネージド リソースを含む基本クラス
マネージド リソースのみを所有する基底クラスの dispose パターンを実装する一般的な例を次に示します。
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
手記
前の例では、 ダミーMemoryStream オブジェクトを使用してパターンを示しています。 代わりに、任意の IDisposable を使用できます。
アンマネージ リソースを含む基底クラス
所有するアンマネージ リソースをクリーンアップするために、 Object.Finalize をオーバーライドする基底クラスの dispose パターンを実装する例を次に示します。 この例では、スレッド セーフな方法で Dispose(bool) を実装する方法も示しています。 マルチスレッド アプリケーションでアンマネージド リソースを処理する場合、同期が重要になる場合があります。 前述のように、これは高度なシナリオです。
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
手記
- 前の例では、AllocHGlobalを使用してコンストラクターのアンマネージ ヒープに 10 バイトを割り当て、
Dispose(bool)を呼び出してFreeHGlobalでバッファーを解放します。 これは、説明のためにダミーの割り当てです。 - ここでも、ファイナライザーを実装しないようにすることをお勧めします。 非確定的な最終処理と同期をに委任する前の例と同等のものについては、SafeHandleに関する説明を参照してください。
ヒント
C# では、をオーバーライドすることではなく、Object.Finalizeを提供することで、ファイナライズを実装します。 Visual Basic では、Protected Overrides Sub Finalize()を使用してファイナライザーを作成します。
派生クラスの dispose パターンを実装する
IDisposable の基底クラスの実装は派生クラスによって継承されるため、IDisposable インターフェイスを実装するクラスから派生したクラスは、IDisposable.Disposeを実装しないでください。 代わりに、派生クラスをクリーンアップするには、次の情報を指定します。
- 基底クラス メソッドをオーバーライドし、派生クラスの実際のクリーンアップを実行する
protected override void Dispose(bool)メソッド。 このメソッドは、引数として破棄状態 (base.Dispose(bool)パラメーター) を渡すMyBase.Dispose(bool)(Visual Basic のbool disposing) メソッドも呼び出す必要があります。 - アンマネージ リソースをラップする SafeHandle から派生したクラス (推奨)、または Object.Finalize メソッドのオーバーライドのいずれか。
SafeHandle クラスには、コーディングが不要なファイナライザーが用意されています。 ファイナライザーを提供する場合は、
Dispose(bool)引数を使用してfalseオーバーロードを呼び出す必要があります。
セーフ ハンドルを使用する派生クラスの dispose パターンを実装するための一般的なパターンの例を次に示します。
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
手記
前の例では、SafeFileHandle オブジェクトを使用してパターンを示しています。代わりに、SafeHandle から派生した任意のオブジェクトを使用できます。 この例では、 SafeFileHandle オブジェクトが適切にインスタンス化されない点に注意してください。
Object.Finalizeをオーバーライドする派生クラスの dispose パターンを実装するための一般的なパターンを次に示します。
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
安全なハンドル
オブジェクトのファイナライザーのコードを記述することは、正しく行われなければ問題を引き起こす可能性がある複雑なタスクです。 そのため、ファイナライザーを実装するのではなく、System.Runtime.InteropServices.SafeHandle オブジェクトを構築することをお勧めします。
System.Runtime.InteropServices.SafeHandle は、アンマネージ リソースを識別する System.IntPtr をラップする抽象マネージド型です。 Windows ではハンドルを識別し、Unix ではファイル記述子を識別できます。
SafeHandle は、SafeHandle が破棄されたとき、または SafeHandle へのすべての参照が削除され、SafeHandle インスタンスが終了したときに、このリソースが 1 回だけ解放されるようにするために必要なすべてのロジックを提供します。
System.Runtime.InteropServices.SafeHandle は抽象基本クラスです。 派生クラスは、さまざまな種類のハンドルに対して特定のインスタンスを提供します。 これらの派生クラスは、無効と見なされる System.IntPtr の値と、実際にハンドルを解放する方法を検証します。 たとえば、SafeFileHandleは、開いているファイル ハンドルと記述子を識別するSafeHandleをラップするIntPtrsから派生し、SafeHandle.ReleaseHandle() メソッドをオーバーライドして閉じます (Unix のclose関数または Windows のCloseHandle関数を使用)。 アンマネージ リソースを作成する .NET ライブラリのほとんどの API は、生のポインターを返すのではなく、 SafeHandle でラップし、必要に応じてその SafeHandle を返します。 アンマネージ コンポーネントと対話し、アンマネージ リソースの IntPtr を取得する状況では、独自の SafeHandle 型を作成してラップすることができます。 その結果、ファイナライザーを実装する必要がある非SafeHandle 型はほとんどありません。 ほとんどのディスポーザブルパターン実装では、通常は他のマネージドリソースがラップされており、その中にはオブジェクトSafeHandleであることもあります。
カスタム セーフ ハンドルを使用して dispose パターンを実装する
次のコードは、 SafeHandleを実装してアンマネージ リソースを処理する方法を示しています。
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
手記
DisposableBaseWithSafeHandle クラスの動作は、前の例のDisposableBaseWithFinalizer クラスの動作と同じですが、ここで示したアプローチの方が安全です。
- SafeHandleがファイナライザーを処理するため、ファイナライザーを実装する必要はありません。
- スレッドの安全性を保証するために同期を行う必要はありません。
DisposeのDisposableBaseWithSafeHandle実装には競合状態がありますが、SafeHandleはSafeHandle.ReleaseHandleが 1 回だけ呼び出されることを保証します。
.NET のビルトインセーフハンドル
Microsoft.Win32.SafeHandles 名前空間の次の派生クラスは、安全なハンドルを提供します。
| クラス | 保有するリソース |
|---|---|
| SafeFileHandle SafeMemoryMappedFileHandle SafePipeHandle |
ファイル、メモリマップドファイル、およびパイプ |
| SafeMemoryMappedViewHandle | メモリ ビュー |
| SafeNCryptKeyHandle SafeNCryptProviderHandle SafeNCryptSecretHandle |
暗号化コンストラクト |
| SafeRegistryHandle | レジストリ キー |
| SafeWaitHandle | 待機ハンドル |
関連項目
.NET