タイプとタイプ変換

タイプは、AS 構文または変換演算子を使用して他のタイプに変換できます。

値タイプ、参照タイプ、ボックス化

マネージ COBOL では、次のタイプを区別します。

  • 値タイプ (.NET の binary-long や System.DateTime など)。値タイプのデータ項目には実際の値が含まれます。例えば、COBOL binary-long データ項目には 32 ビット整数が含まれます。
  • オブジェクト・ヒープで割り当てられる参照タイプ。参照タイプのデータ項目は、オブジェクト・ヒープへの参照を保持します。参照タイプは、ガベージ・コレクタの管理下にあります。

すべての値タイプは、ボックス化と呼ばれるプロセスで参照タイプに変わることがあります。例えば、オブジェクト参照を、binary-long などの値タイプに設定できます。

ボックス化は、必要に応じて自動で行われます。例えば、オブジェクトをパラメータとして予測するメソッドに値タイプをパラメータとして渡す場合などです。

明示的にボックス化するには、値タイプを汎用タイプ (.NET COBOL の System.Object や JVM COBOL の java.lang.Object など) に割り当てます。

値タイプのボックス化を解除して、元の値タイプを復元できます。

データ項目の定義でタイプ classname を指定する場合:

  • classname が参照タイプを表す場合、参照タイプ・オブジェクトを取得します。
  • classname が値タイプを表す場合、値タイプ・オブジェクトを取得します。

ボックス化の際に、値がオブジェクト・ヒープにコピーされ、参照がオブジェクト・ヒープに戻されます。参照がアクティブではなくなった場合 (オブジェクト・ヒープに対して保持するものがプログラム内にないため)、オブジェクト・ヒープのスペースは、ガベージ・コレクタで最終的に再取得されます。

値タイプのサンプルを参照してください。このサンプルは [スタート > すべてのプログラム > Micro Focus Enterprise Developer > Visual COBOL Samples] にあります。

タイプ情報

すべてのクラスにはルート・オブジェクトが関連付けられています。このルート・オブジェクトを使用して、そのフィールドやメソッドなどのクラスに関する情報を取得できます。タイプ情報を取得するには、次の方法を使用します。

  • .NET COBOL では GetType() - オブジェクト参照の場合は System.Type オブジェクトを取得します。
  • JVM COBOL では getClass() - オブジェクト参照のクラスを取得するには java.lang.Object を取得します。
  • TYPE OF - クラス、インターフェース、デリゲート、または列挙の場合は System.Type オブジェクトを取得します。
    imperative-clause TYPE OF object

例えば、.NET COBOL では次のようになります。

*> タイプ情報
01 x binary-long.
display x::GetType            *> System.Int32 を印刷する
display type of binary-long   *> System.Int32 を印刷する
display x::GetType::Name      *> Int32 を印刷する

例えば、JVM COBOL では次のようになります。

*> タイプ情報
01 x binary-long.
display x::getClass           *> System.Int32 を印刷する
display type of binary-long   *> System.Int32 を印刷する
display x::getClass::Name     *> Int32 を印刷する

タイプ変換演算子

変換演算子は、あるデータ・タイプ (整数に定義したタイプなど) のデータ項目を別のデータ・タイプに変換します。変換演算子はオーバーロードできるため、適切な変換演算子が呼び出しコードのパラメータ・タイプに従って使用されます。

例えば、時間と分を含むタイプ Timer は、次の変換演算子を使用して binary-long として分に変換されます。

       set myMins to timer3 ...
       operator-id Implicit.
       procedure division using value a as type Timer 
                          returning b as binary-long.
            set b to a::pHour * 60 + a::pMins
       end operator.      

同様に、次の変換演算子を使用して、binary-long データ項目 (分を表す) から、時間と分で表されるタイプ Timer に変換できます。

       set timer4 to myMins ...
       operator-id Implicit.
       procedure division using value a as binary-long 
                          returning b as type Timer.
             set b to new Timer
             if a >= 60
                 set b::pHour to 1
                 set b::pMins to a - 60 
             else
                 set b::pMins to a
             end-if
       end operator.

暗黙変換の他に明示変換を定義できます。暗黙変換と明示変換は次のように異なります。

明示変換
明示変換は、変換元のタイプを明示的に提示する文でのみ行われます。例えば、変換演算子が明示として定義される場合、次の 2 番目の文のみが機能します。
       set timer4 to myString                *> 失敗 
       set timer4 to myString as type Timer  *> 成功
       operator-id Explicit.
       01 strH type String.
       01 strM type String.
       01 colonPos  binary-long value 0.
 
       procedure division using value a as String returning b as Type Timer. 
           set b to new Timer()
           set colonPos to a::IndexOf(":")
           try
               set strH to a::Substring(0 colonPos)
               set strM to a::Substring(colonPos + 1 2)
               set b::pHour to type Int32::Parse(strH)
               set b::pMins to type Int32::Parse(strM)
           catch
               display "Invalid time format"
           end-try
       end operator.

変換で情報が失われたり、例外がスローされる可能性がある場合、(暗黙変換ではなく) 明示変換を使用します。上記の例では、文字列にテキストが含まれるか、何らかの理由で文字列が無効になります。この場合、失敗を処理するには try-catch ブロックが必要です。

暗黙変換
暗黙変換は、割り当て、メンバの呼び出し、明示変換などのあらゆる場所で行われます。前述の例を参照してください。

暗黙変換は暗黙的または明示的に呼び出すことができます。例えば、次の文はどちらも暗黙変換を呼び出します。

       set myMins to timer3 
       set myMins to timer3 as binary-long

変換が信頼できる場合 (情報が失われず、例外がスローされない場合)、暗黙変換を使用します。

AS を使用したオブジェクト参照のキャスト

オブジェクト参照は、AS を使用して別のタイプのインスタンスにキャストできます。コンパイラは、操作がタイプ・セーフかどうかをチェックできます。

次の例では、obj-object が System.AppDomain 参照を指し示すことがわかっているため、System.Object から System.AppDomain に向かってクラス階層を上方向にキャストできます。

   
    *> obj-app-domain を obj-object に設定する             *> 非コメント化する場合は失敗
     set obj-app-domain to obj-object as type System.AppDomain *> 成功

キャストはインラインで可能なため、次の操作を実行できます。

display obj-object as type System.AppDomain::FriendlyName

キャストは、ターゲット・タイプ (キャスト先のタイプ) がソース・タイプから直接派生する場合 (あるいはその逆) のみ適しています。次の文では、クラスが階層に関連しないため、System.Type 参照 (obj-type) が System.AppDomain インスタンスを指し示すことはありません。

   
       *>obj-app-domain を obj-type に タイプ System.AppDomain として設定する *> 非コメント化する場合は失敗

キャストが失敗すると、System.InvalidCastException が CLR からスローされます。この例外を避けるには、INSTANCE OF を使用して有効なキャストかどうかを最初にテストするか、例外ブロックでキャストをラップします (詳細は、例外処理の例を参照)。

実際に obj-object が System.Type インスタンスを参照している場合、obj-object が System.AppDomain インスタンスを参照すると断言すると、例外が次のようにスローされます。

   *> 非コメント化する場合、これらの文は失敗  
       *> obj-object を obj-type に設定する                  
       *> obj-app-domain を obj-object にタイプ System.AppDomain として設定する