いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

.NET クラスライブラリ探訪-054 (System.Runtime.CompilerServices.RuntimeHelpers (3))(ExecuteCodeWithGuaranteedCleanup, TryCode, CleanupCode, ReliabilityContract, CER)


今回は、System.Runtime.CompilerServices.RuntimeHelpersクラスのExecuteCodeWithGuaranteedCleanupメソッドについて
ちょこっとメモメモ。前回、前々回の続きとなっています。

  • .NET クラスライブラリ探訪-052 (System.Runtime.CompilerServices.RuntimeHelpers)(オブジェクト識別ID取得, 特殊なGetHashCode, RuntimeHelpers.PrepareMethod, RuntimeHelpers.GetHashCode)
  • .NET クラスライブラリ探訪-053 (System.Runtime.CompilerServices.RuntimeHelpers (2))(PrepareConstrainedRegions, ReliabilityContract, CER, Consistency, 信頼性のコントラクト, 事前コンパイル)


RuntimeHelpersクラスには、前回記述したPrepareConstrainedRegionsメソッドと
同様の動きをするメソッドとして、ExecuteCodeWithGuaranteedCleanupメソッドというのもあります。
このメソッドもPrepareConstrainedRegionsメソッドと同じく、コード本体をCERとして実行します。


違いは、PrepareConstrainedRegionsメソッドが呼び出されたメソッドのcatch, finallyブロックを
CERとしてマークするのに対して、ExecuteCodeWithGuaranteedCleanupメソッドの場合は
明示的に実行コードとクリーンアップコードをdelegateで指定します。


メソッド書式は以下のようになっています。

public static void ExecuteCodeWithGuaranteedCleanup(
                              RuntimeHelpers.TryCode     code, 
                              RuntimeHelpers.CleanupCode backoutCode, 
                              object                     userData)

指定するdelegateはTryCodeデリゲートとCleanupCodeデリゲートの2つです。

public delegate void TryCode(object userData)
public delegate void CleanupCode(object userData, bool exceptionThrown)


CERの詳細については、MSDNの以下のトピックに詳しく記載されています。


以下サンプルです。前回のサンプルを改変したものとなっています。

  #region RuntimeHelpersSamples-03
  /// <summary>
  /// RuntimeHelpersクラスのサンプルです。
  /// </summary>
  public class RuntimeHelpersSamples03 : IExecutable
  {
    // サンプルクラス
    static class SampleClass
    {
      static SampleClass()
      {
        Console.WriteLine("SampleClass static ctor()");
      }

      //
      // このメソッドに対して、CER内で利用できるよう信頼性のコントラクトを付与.
      // ReliabilityContractAttributeおよびConsistencyやCerは
      // System.Runtime.ConstrainedExecution名前空間に存在する.
      //
      [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
      internal static void Print()
      {
        Console.WriteLine("SampleClass.Print()");
      }
    }
    
    public void Execute()
    {
      //
      // ExecuteCodeWithGuaranteedCleanupメソッドは, PrepareConstrainedRegionsメソッドと
      // 同様に、コードをCER(制約された実行環境)で実行するメソッドである。
      //
      // PrepareConstrainedRegionsメソッドが呼び出されたメソッドのcatch, finallyブロックを
      // CERとしてマークするのに対して、ExecuteCodeWithGuaranteedCleanupメソッドは
      // 明示的に実行コード部分とクリーンアップ部分 (バックアウトコード)を引数で渡す仕様となっている。
      //
      // ExecuteCodeWithGuaranteedCleanupメソッドは
      // TryCodeデリゲートとCleanupCodeデリゲート、及び、userDataを受け取る.
      //
      // public delegate void TryCode(object userData)
      // public delegate void CleanupCode(object userData, bool exceptionThrown)
      //
      // 前回のサンプルと同じ動作を行う.
      RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(Calc, Cleanup, null);
    }
    
    void Calc(object userData)
    {
      for (int i = 0; i < 10; i++)
      {
        Console.Write("{0} ", (i + 1));
      }
      
      Console.WriteLine("");
    }
    
    void Cleanup(object userData, bool exceptionThrown)
    {
      SampleClass.Print();
    }
  }
  #endregion


以下、実行結果です。

  SampleClass static ctor()
  1 2 3 4 5 6 7 8 9 10 
  SampleClass.Print()


tryブロック内のコードが実行される前に、事前コンパイル(メソッドが準備される)ので
先に静的コンストラクタが実行されていることが分かります。


以下、参考資料です。


================================
過去の記事については、以下のページからご参照下さい。

サンプルコードは、以下の場所で公開しています。