「ネオ写経」のすすめ
新型コロナウイルス対応で外出の自粛が求められる中、みなさまいかがお過ごしでしょうか。
ろくにテレワーク環境も整っていないのに、「とにかくテレワークだ!」的に導入されてしまった事業所も、それなりにあると思います。
個人的には、この期間は〈終息後のダメージ回復〉を効果的に行うために個人が力量を高める機会ととらえるのが良いと思います。それができる余裕のある業界に限られますが……。
「ネオ写経」とは
私が勝手に考えました。
もともと、プログラミング界隈で「写経」といえば、サンプル・コードの類を写すこと。(ですよね?)
ただ、私は「写経」というものをしたことがほぼない。写しているうちに、「あら? じゃあ、ここはこうした方がおもろいやんけ。」とか、「ついでにこうしといたれ。」みたいなのが出てくるから、「般若心経」を写していたはずなのに、なぜか「あほだら経」が出来上がっていた、ということが起こる。
そんな私が考えた「ネオ写経」とは!?
既存クラスをラップしたクラスを作る。
これ。
ニセFileSystemObjectを作る
FileSystemObjectは便利だ。
しかも、プロパティ名とかメソッド名は、さすがプロが作っただけあって、実に良くできている。コードが実に読みやすくなる。
ところが、デフォルトでは使えない。
いちいち参照設定をせねばならん。
もちろんCreateObjectを使えば参照設定せずにすむ。
しかし、これだとObject型変数に突っ込んで使用することになり、コーディング時に入力補完の恩恵が得られずイマイチ。
もちろん、コーディング時に参照設定をしておき、完成したら参照設定を切る、という方法もあるにはあるが、それはそれでメンドクサイ。
だったら、FileSystemObjectクラスをラップしたFileSystemObjectクラスを自作しちまえばいいんでねえの!
コンストラクタ
これは簡単。Class_InitializeでScripting.FileSystemObjectクラスのインスタンスを得ればよい。
まず、プロジェクトにクラスモジュールを挿入し、オブジェクト名をFileSystemObjectにする。そして、クラスモジュールに次のコードを書く。
クラスモジュール FileSystemObject
'Declarations Section'
'Module Level Variables'
Private fsObj As Object
'Constructor'
Private Sub Class_Initialize()
Set fsObj = CreateObject("Scripting.FileSystemObject")
End Sub
これだけ。
これで、プロパティとかメソッドをこの変数fsObjを経由して呼び出すようにすればいい。
プロパティとメソッドの実装(笑)
大袈裟な見出しだが、プロパティをメソッドを実装(笑)するときの教科書が、おれたちの「オブジェクト ブラウザー」様だ!
「ブラウザー」と延ばしているところがボスキャラ感があっていいよね。
[F2]キーを押すか何かして、「オブジェクト ブラウザー」を開き、FileSystemObjectを指定すると、

こんなふうにメンバを確認することができるし、

こんなふうに各メンバの実装方法を確認することもできる。
あとはコーディングあるのみ!
……である!
プロパティの実装(笑)
……といっても、FileSystemObjectにはプロパティは一つしかない。これは意外だった。なんと、Drivesコレクションを返すDrivesプロパティしかないのだ。
実装方法は、オブブラ(略すなw)によると、
Property Drives As Drives
とのこと。
もちろん、このまま打ち込んでもコンパイルエラーになるので、脳内でコードを補完して
Public Prooerty Get Drives() As Drives
とする。
もちろん、Microsoft Scripting Runtimeを参照設定しないのだから、As Drivesではまずい。で、
Public Prooerty Get Drives() As Object
と、返り値をObject型に改めておく。
あとは中身。
Dim ret As Object Set ret = fsObj.Drives '……(1)' Set Drives = ret '……(2)'
これでいい。変数fsObjはモノホンのFileSystemObjectクラスのインスタンスを指しているから、そのDrivesプロパティの返り値はもちろんモノホンのDrivesコレクション。
だから、まずは(1)の
Set ret = fsObj.Drives
で返り値用の変数retにモノホンのDrivesコレクションを突っ込んでおき、(3)の
Set Drives = ret
でニセのDrivesプロパティの返り値としてやる。
プロシージャ全体は
Public Prooerty Get Drives() As Object Dim ret As Object Set ret = fsObj.Drives Set Drives = ret End Property
こう。
メソッドの実装(笑)
メソッドも基本的にはこの方法。

このように、オブブラ(笑)で、
Sub/Functionの別- 引数リスト
- 引数が
Optionalかどうか - 返り値の型
を確認し、それに応じてコーディングすればいい。
たとえば先の画像のCreateTextFileメソッドならば、
- 種別は
Function - 引数は
FileName、OverWrite、Unicodeの三つ。 - 引数
OverWrite・UnicodeはOptional - 返り値は
TextStream型
なので、それに応じてコーディングする。
Public Function CreateTextFile( _ ByVal FileName As String, _ Optional ByVal OverWrite As Boolean = True, _ Optional ByVal Unicode As Boolean = False) As TextStream
となる。
しかし、TextStreamクラスもScripting.FileSystemObjectクラスのメンバなので、Objectにする。
Public Function CreateTextFile( _ ByVal FileName As String, _ Optional ByVal OverWrite As Boolean = True, _ Optional ByVal Unicode As Boolean = False) As Object
こうなる。
プロシージャ全体は
Public Function CreateTextFile( _ ByVal FileName As String, _ Optional ByVal OverWrite As Boolean = True, _ Optional ByVal Unicode As Boolean = False) As Object Dim ret As Object Set ret = fsObj.CreateTextFile(FileName, OverWrite, Unicode) Set CreateTextFile = ret End Function
こう。
引数が列挙体型のやつがある
あと、メソッドの中には引数がScripting.FileSystemObjectの中で定義された列挙体であるものがある。
たとえば、

このGetStandardStreamメソッドの場合、
Function GetStandardStream(StandardStreamType As StandardStreamTypes, [Unicode As Boolean = False]) As TextStream
とあるように、第1引数StandardStreamTypeがStandardStreamTypesという見慣れない型である。
こいつは、オブブラ(笑)で見ると

となっているように、Scriptingクラスで定義された列挙体なんである。
当然、Microsoft Scripting Runtimeを参照設定していないと使えない。
そういうときはどうするか。
このニセFileSystemObjectクラスモジュール内でPublic Enumにしてしまえばいいのである!
'Declarations Section' 'Constants' Public Enum StandardStreamTypes StdIn = 0 StdOut = 1 StdErr = 2 End Enum
列挙体のメンバがそれぞれどの数値を表しているのか、というのもオブブラ(笑)先輩を見ればわかる。

ほれ。こんなふうに。
Scripting.__MIDL___MIDL_itf_scrrun_0001_0001_0003ちゅうのは何のことやらわからんがw
おわりに
上記のようにして、ひたすらプロパティ・メソッドを実装(笑)し続けることを、「ネオ写経」と呼んでおります。
オブジェクトの仕組みがよくわかって実に勉強になります。
「新型コロナ自粛で勉強ぐらいしかすることがない」という人は、一度やってみてはいかがでしょうか?
ちなみに、FileSystemObjectは、配下にDrives、Drive、Folders、Folder、Files、File、TextStreamというScripting内のオブジェクトを抱えているので、本気でFileSystemObjectクラスを丸ごとラップしようと思ったら、全部で八つもクラスモジュールを作ることになりますw

こんなふうに。
特に、Folders-Folderのような階層構造を持つクラスを表現するのにめちゃくちゃ頭を使いましたw