この記事は機械翻訳されています。英語版の記事を表示するには、[英語] のチェック ボックスをオンにしてください。また、テキストにマウス ポインターを合わせると、ポップアップ ウィンドウに英語のテキストを表示することもできます。
翻訳
英語

Object.Finalize メソッド ()

 

公開日: 2016年10月

オブジェクトがガベージ コレクションにより収集される前に、そのオブジェクトがリソースを解放し、その他のクリーンアップ操作を実行できるようにします。

名前空間:   System
アセンブリ:  mscorlib (mscorlib.dll 内)

protected virtual void Finalize()

Finalizeオブジェクトが破棄される前に、現在のオブジェクトによって保持されているアンマネージ リソースのクリーンアップ操作を実行するメソッドを使用します。 メソッドが保護されているためおよび派生クラスによって、またはこのクラスによってのみアクセスできます。

このセクションの内容:

Objectクラスの実装を提供なし、Finalizeメソッド、および、ガベージ コレクターから派生した型をマークしませんObject終了がオーバーライドされない限り、Finalizeメソッドです。

型をオーバーライドしている場合、Finalizeメソッド、ガベージ コレクターにエントリを追加、型のインスタンスごとにファイナライザー キューと呼ばれる内部構造体。 ファイナライザーのキューには、すべてのオブジェクトが終了コードは、ガベージ コレクターが自らのメモリを解放する前に実行する必要があります、マネージ ヒープ内のエントリが含まれています。 ガベージ コレクターを呼び出して、Finalizeメソッドは、次の条件下で自動的に。

  • ガベージ コレクターがオブジェクトへの呼び出しによって終了処理から除外されている場合を除きには、オブジェクトがアクセス可能でないことを検出したら、GC.SuppressFinalizeメソッドです。

  • アプリケーション ドメインのシャット ダウン中にオブジェクトが終了処理から除外されている場合を除き、します。 シャット ダウン中、引き続きアクセスできるものオブジェクトが完了しました。

Finalize自動的に 1 回だけ呼び出す特定のインスタンスでオブジェクトが再などのメカニズムを使用して、登録されている場合を除き、GC.ReRegisterForFinalizeGC.SuppressFinalizeメソッドが、その後に呼び出されていません。

Finalize操作には、次の制限があります。

  • ファイナライザーの実行の正確な時間は、定義されていません。 リソースの確定的に解放をように、クラスのインスタンスを実装する、Closeメソッドを提供したり、IDisposable.Dispose実装します。

  • 2 つのオブジェクトのファイナライザーは、1 つのオブジェクトを指す他の場合でも、特定の順序で実行する保証はありません。 つまり、オブジェクト A がオブジェクト B への参照を両方ファイナライザーがある場合は、オブジェクト B 可能性がありますが既に終了されているオブジェクトのファイナライザーの開始時にします。

  • ファイナライザーが実行されているスレッドは、指定されていません。

Finalizeメソッドが完了するまで実行されないか、次の例外的な状況でまったく実行されない可能性があります。

  • 別のファイナライザーが無期限にブロックした場合 (、無限ループに移動しようとすることはありませんを入手してなどのロックの取得)。 ランタイムがファイナライザーを完了するまで実行しようとするとため、その他のファイナライザー可能性がある場合は呼び出されませんファイナライザー ブロック無期限にします。

  • 場合は、ランタイムをクリーンアップする機会を与えることがなく、プロセスを終了します。 この場合、ランタイムのプロセスの終了の最初の通知はあります通知です。

ランタイムは、ファイナライズ可能なオブジェクトの数が減少し続けます中にのみ、シャット ダウン中にオブジェクトを最終処理を続行します。

場合FinalizeまたはのオーバーライドFinalize、例外をスローし、ランタイムが、既定のポリシーをオーバーライドするアプリケーションによってホストされていない、プロセスとはアクティブなランタイムが終了するtry/finallyブロックまたはファイナライザーを実行します。 この動作は、ファイナライザーが解放またはリソースを破棄できない場合、プロセスの整合性を確保します。

オーバーライドする必要がありますFinalizeなどのアンマネージ リソースを使用するクラス ファイル ハンドルやデータベース接続ガベージ コレクション中にそれらを使用するマネージ オブジェクトが破棄されたときに解放する必要があります。

System_CAPS_important重要

場合、SafeHandleオブジェクトが使用可能なアンマネージ リソースをラップする、推奨される代替手段は、セーフ ハンドルの dispose パターンを実装し、無効にするFinalizeです。 詳細については、次を参照してください。代わりに、SafeHandleセクションです。

Object.Finalizeメソッドは既定では、何しますが、オーバーライドする必要がありますFinalizeのみ必要であれば、アンマネージ リソースを解放するだけです。 メモリを再利用には、少なくとも 2 つのガベージ コレクションが必要とするために終了操作を実行する場合は、かなり長くかかるに傾向があります。 さらに、オーバーライドする必要があります、Finalize参照用のメソッドの型だけです。 共通言語ランタイムは、参照型のみを終了します。 値型でファイナライザーは無視されます。

すべての実装のFinalize派生型での基本データ型の実装を呼び出す必要がありますFinalizeです。 これを呼び出すアプリケーション コードが許可されている場合だけFinalizeです。

System_CAPS_noteメモ

C# コンパイラを上書きすることはできません、Finalizeメソッドです。 実装することでファイナライザーを用意する代わりに、デストラクタークラスです。 C# のデストラクターでは、その基本クラスのデストラクターは、自動的に呼び出します。

Visual C を実装する独自の構文もが用意されています、Finalizeメソッドです。 詳細については、の「デストラクターとファイナライザー」セクションを参照してください。方法: クラスと構造体 (C++ CLI) 定義および使用です。

ガベージ コレクションは非決定的であるため、ガベージ コレクターが終了処理を実行すると正確にわかっていません。 リソースを解放する、すぐにこともできますを実装する、 dispose パターンIDisposableインターフェイスです。 IDisposable.Dispose 、アンマネージ リソースを解放する、クラスのコンシューマーによって実装を呼び出すことができ、使用することができます、Finalizeアンマネージ リソースを解放するメソッド イベントで、Disposeメソッドは呼び出されません。

Finalizeガベージ コレクション中にクリーンアップされた後に、オブジェクト (つまり、オブジェクトにアクセスできるように再度) 復活させる方法を含む、ほぼすべてのアクションを実行することができます。 ただし、オブジェクトできますのみ再生できるは 1 回です。Finalizeガベージ コレクション中に再生されたオブジェクトで呼び出すことができません。 1 つのアクションがあることの実装Finalizeを渡す必要があります: が例外をスローする必要がありますしません。

信頼性の高いファイナライザーの作成が多くの場合、困難ですが、アプリケーションの状態に関する仮定をすることはできないためなど、未処理のシステム例外OutOfMemoryExceptionStackOverflowExceptionファイナライザーを終了します。 派生したオブジェクトを使用するアンマネージ リソースを解放するには、クラスのファイナライザーを実装するには、代わりに、System.Runtime.InteropServices.SafeHandleアンマネージ リソースをラップするクラスし、ファイナライザーせず、dispose パターンを実装します。 .NET Framework の次のクラスには、Microsoft.Win32から派生した名前空間System.Runtime.InteropServices.SafeHandle:

次の例では、 dispose パターンオーバーライドする代わりにセーフ ハンドルを使った、Finalizeメソッドです。 定義する、FileAssociation特定のファイル拡張子を持つファイルを処理するアプリケーションのレジストリ情報をラップするクラス。 として返される 2 つのレジストリ ハンドルoutWindows によってパラメーター RegOpenKeyEx関数の呼び出しに渡される、SafeRegistryHandleコンス トラクターです。 型の保護されたDisposeメソッドを呼び出します、SafeRegistryHandle.Disposeこれら 2 つのハンドルを解放します。

using Microsoft.Win32.SafeHandles;
using System;
using System.ComponentModel;
using System.IO;
using System.Runtime.InteropServices;

public class FileAssociationInfo : IDisposable
{
   // Private variables.
   private String ext;
   private String openCmd;
   private String args;
   private SafeRegistryHandle hExtHandle, hAppIdHandle;

   // Windows API calls.
   [DllImport("advapi32.dll", CharSet= CharSet.Auto, SetLastError=true)]
   private static extern int RegOpenKeyEx(IntPtr hKey, 
                  String lpSubKey, int ulOptions, int samDesired,
                  out IntPtr phkResult);
   [DllImport("advapi32.dll", CharSet= CharSet.Unicode, EntryPoint = "RegQueryValueExW",
              SetLastError=true)]
   private static extern int RegQueryValueEx(IntPtr hKey,
                  string lpValueName, int lpReserved, out uint lpType, 
                  string lpData, ref uint lpcbData);   
   [DllImport("advapi32.dll", SetLastError = true)]
   private static extern int RegSetValueEx(IntPtr hKey, [MarshalAs(UnmanagedType.LPStr)] string lpValueName,
                  int Reserved, uint dwType, [MarshalAs(UnmanagedType.LPStr)] string lpData,
                  int cpData);
   [DllImport("advapi32.dll", SetLastError=true)]
   private static extern int RegCloseKey(UIntPtr hKey);

   // Windows API constants.
   private const int HKEY_CLASSES_ROOT = unchecked((int) 0x80000000);
   private const int ERROR_SUCCESS = 0;

    private const int KEY_QUERY_VALUE = 1;
    private const int KEY_SET_VALUE = 0x2;

   private const uint REG_SZ = 1;

   private const int MAX_PATH = 260;

   public FileAssociationInfo(String fileExtension)
   {
      int retVal = 0;
      uint lpType = 0;

      if (!fileExtension.StartsWith("."))
             fileExtension = "." + fileExtension;
      ext = fileExtension;

      IntPtr hExtension = IntPtr.Zero;
      // Get the file extension value.
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), fileExtension, 0, KEY_QUERY_VALUE, out hExtension);
      if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);
      // Instantiate the first SafeRegistryHandle.
      hExtHandle = new SafeRegistryHandle(hExtension, true);

      string appId = new string(' ', MAX_PATH);
      uint appIdLength = (uint) appId.Length;
      retVal = RegQueryValueEx(hExtHandle.DangerousGetHandle(), String.Empty, 0, out lpType, appId, ref appIdLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);
      // We no longer need the hExtension handle.
      hExtHandle.Dispose();

      // Determine the number of characters without the terminating null.
      appId = appId.Substring(0, (int) appIdLength / 2 - 1) + @"\shell\open\Command";

      // Open the application identifier key.
      string exeName = new string(' ', MAX_PATH);
      uint exeNameLength = (uint) exeName.Length;
      IntPtr hAppId;
      retVal = RegOpenKeyEx(new IntPtr(HKEY_CLASSES_ROOT), appId, 0, KEY_QUERY_VALUE | KEY_SET_VALUE,
                            out hAppId);
       if (retVal != ERROR_SUCCESS) 
         throw new Win32Exception(retVal);

      // Instantiate the second SafeRegistryHandle.
      hAppIdHandle = new SafeRegistryHandle(hAppId, true);

      // Get the executable name for this file type.
      string exePath = new string(' ', MAX_PATH);
      uint exePathLength = (uint) exePath.Length;
      retVal = RegQueryValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, out lpType, exePath, ref exePathLength);
      if (retVal != ERROR_SUCCESS)
         throw new Win32Exception(retVal);

      // Determine the number of characters without the terminating null.
      exePath = exePath.Substring(0, (int) exePathLength / 2 - 1);
      // Remove any environment strings.
      exePath = Environment.ExpandEnvironmentVariables(exePath);

      int position = exePath.IndexOf('%');
      if (position >= 0) {
         args = exePath.Substring(position);
         // Remove command line parameters ('%0', etc.).
         exePath = exePath.Substring(0, position).Trim();
      }
      openCmd = exePath;   
   }

   public String Extension
   { get { return ext; } }

   public String Open
   { get { return openCmd; } 
     set {
        if (hAppIdHandle.IsInvalid | hAppIdHandle.IsClosed)
           throw new InvalidOperationException("Cannot write to registry key."); 
        if (! File.Exists(value)) {
           string message = String.Format("'{0}' does not exist", value);
           throw new FileNotFoundException(message); 
        }
        string cmd = value + " %1";
        int retVal = RegSetValueEx(hAppIdHandle.DangerousGetHandle(), String.Empty, 0, 
                                   REG_SZ, value, value.Length + 1);
        if (retVal != ERROR_SUCCESS)
           throw new Win32Exception(retVal);                          
     } }

   public void Dispose() 
   {
      Dispose(true);
      GC.SuppressFinalize(this);
   }   

   protected void Dispose(bool disposing)
   {
      // Ordinarily, we release unmanaged resources here; 
      // but all are wrapped by safe handles.

      // Release disposable objects.
      if (disposing) {
         if (hExtHandle != null) hExtHandle.Dispose();
         if (hAppIdHandle != null) hAppIdHandle.Dispose();
      }
   }
}

次の例では、あることを確認、Finalizeオブジェクトを上書きする場合に、メソッドが呼び出されますFinalizeは破棄されます。 なお、実稼働アプリケーションで、Finalizeオブジェクトによって保持されているアンマネージ リソースを解放するメソッドはオーバーライドされます。 なお、c# の例にオーバーライドする代わりにデストラクターが提供されている、Finalizeメソッドです。

using System;
using System.Diagnostics;

public class ExampleClass
{
   Stopwatch sw;

   public ExampleClass()
   {
      sw = Stopwatch.StartNew();
      Console.WriteLine("Instantiated object");
   } 

   public void ShowDuration()
   {
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }

   ~ExampleClass()
   {
      Console.WriteLine("Finalizing object");
      sw.Stop();
      Console.WriteLine("This instance of {0} has been in existence for {1}",
                        this, sw.Elapsed);
   }
}

public class Demo
{
   public static void Main()
   {
      ExampleClass ex = new ExampleClass();
      ex.ShowDuration();
   }
}
// The example displays output like the following:
//    Instantiated object
//    This instance of ExampleClass has been in existence for 00:00:00.0011060
//    Finalizing object
//    This instance of ExampleClass has been in existence for 00:00:00.0036294

For an additional example that overrides the M:System.Object.Finalize method, see the M:System.GC.SuppressFinalize(System.Object) method.

ユニバーサル Windows プラットフォーム
8 以降で使用可能
.NET Framework
1.1 以降で使用可能
ポータブル クラス ライブラリ
サポート対象: 移植可能 .NET プラットフォーム
Silverlight
2.0 以降で使用可能
Windows Phone Silverlight
7.0 以降で使用可能
Windows Phone
8.1 以降で使用可能
トップに戻る
表示: