2006年07月23日
川俣晶の縁側ソフトウェア技術雑記total 11555 count

VB6の亡霊が甦る!? Microsoft.VisualBasic.CallType列挙型にGet, Setの他に滅んだはずのLetがある理由!!

Written By: 川俣 晶連絡先

 Visual BasicにはCallByNameという関数があるよ、とbiacさんから教えて頂きました。

 言語仕様は原稿執筆のために一通り目を通していますが、Microsoft.VisualBasic名前空間の中身は全て見たわけではないので、気付かなかったものもあります。

 これは、メソッド等を名前で呼び出すもので、簡易なリフレクションのようなもの……と捉えることができます。

 面白そうだから簡単なテストプログラムを1本書いてみようと取り組んだところ、意外にも私好みの問題に突き当たりました。

 それは、以下のようなことです。

見出された問題 §

  • Visual Basic 6.0のプロパティの操作にはGet/Set/Letの3種類が存在する
  • Visual Basic.NET以降はこれがGet/Setの2種類に集約されLetが消えた
  • CallByName関数で指定可能な呼び出しスタイルはMethod, Get, Set, Letの4種類
  • Methodはプロパティ用ではなくメソッド用なので除外すると、Letを含む3種類が存在する
  • しかし、Visual Basic.NET以降で作成されたオブジェクトにはLetの対象はあり得ない
  • このLetは何のために存在する? 何の意味もない値? 互換性のために残されたもの? それとも意味がある?

疑問に対する答 §

 いろいろ調べた結果、CallByName.Letを使用している例(Understanding the Word Object Model from a .NET Developer's Perspective)が見つかりました。Wordのオブジェクトを呼び出す事例で、おそらくCOMオブジェクトです。

 つまり、COMとの互換性ラッパを経由してCOMオブへジェクトを呼び出す場合にも、CallByName関数は使用されるということです。

 そして、COMの世界のプロパティにはGet, Set, Letの3種類が存在します。これをストレートにサポートするためには、Letが必要とされるわけです。

 結論は以下のようになります。

  • CallByName.Letは意味のある値。けしてダミー値ではない
  • COMオブジェクトを直接呼び出すプログラムを作成するプログラマは使う可能性がある
  • COMオブジェクトを直接呼び出すプログラムを扱わないプログラマが使う可能性は(おそらく)無い
  • Visual Basic以外のプログラマ(C#等)でも、Microsoft.VisualBasic.CallByNameメソッドを使うことでCOMオブジェクトを呼び出すプログラムを作成する可能性があり得、その場合はCallByName.Letを使うかもしれない (上記の事例はVBだけでなくC#のサンプルもこれを使って記述されている)

検証プログラム §

 Visual Basic 2005, コンソール アプリケーション。COM版BlatJをregsvr32してからプロジェクトの参照に入れる必要あり。

Module Module1

    Sub Main()

        ' CallType.Methodの使用例

        Dim hello As String = "hello"

        ' 直接呼び出し

        Console.WriteLine(hello.ToUpper())

        ' CallByName呼び出し

        Console.WriteLine(CallByName(hello, "ToUpper", CallType.Method))

        ' CallType.Getの使用例

        Dim sb As New System.Text.StringBuilder

        ' 直接呼び出し

        sb.Append("ab")

        Console.WriteLine(sb.Length)

        ' CallByName呼び出し

        sb.Append("cd")

        Console.WriteLine(CallByName(sb, "Length", CallType.Get))

        ' CallType.Setの使用例

        ' 直接呼び出し

        sb.Length = 2

        Console.WriteLine(sb.Length)

        ' CallByName呼び出し

        Dim dummy1 As Object = CallByName(sb, "Length", _

            CallType.Set, 1)

        Console.WriteLine(sb.Length)

        ' CallType.Letの使用例

        Dim comblat As New COMBLATLib.Blat()    ' COM版BlatJを使用

        ' 直接呼び出し

        comblat.Subject = "test1"

        Console.WriteLine(comblat.Subject)

        ' CallByName呼び出し

        Dim dummy2 As Object = CallByName(comblat, "Subject", _

            CallType.Let, "test2")

        Console.WriteLine(comblat.Subject)

    End Sub

End Module

実行結果 §

HELLO

HELLO

2

4

2

1

test1

test2

念のための補足 §

 上記のソースでは、文字列をLetで扱っています。.NET Frameworkでは文字列はオブジェクトなので参照型になります。それゆえに、LetではなくSetで扱う対象であるかのように思えますが、VB6/COMの文字列は基本データ型の一部なのでLetで扱う範疇に入ります。

 という説明が妥当かどうか確認しようと、資料を調べようとして挫折しました (汗。

Facebook

このコンテンツを書いた川俣 晶へメッセージを送る

[メッセージ送信フォームを利用する]

メッセージ送信フォームを利用することで、川俣 晶に対してメッセージを送ることができます。

この機能は、100%確実に川俣 晶へメッセージを伝達するものではなく、また、確実に川俣 晶よりの返事を得られるものではないことにご注意ください。

このコンテンツへトラックバックするためのURL

http://mag.autumn.org/tb.aspx/20060723164308
サイトの表紙【技術雑記】の表紙【技術雑記】のコンテンツ全リスト 【技術雑記】の入手全リスト 【技術雑記】のRSS1.0形式の情報このサイトの全キーワードリスト 印刷用ページ

管理者: 川俣 晶連絡先

Powered by MagSite2 Version 0.33 (Alpha-Test) Copyright (c) 2004-2018 Pie Dey.Co.,Ltd.