VBA用LINQ(作成中)

VBALINQ to Objects 「っぽい」ことができるものを作成中。

OneDrive内の「M_Sample」モジュール

GitHub - imihito/VBALinq(碌に使ったことがないのでちゃんと使えてるかどうか…)

基本方針

やりたいこと

VBAで要素の集合に対してLINQ to Objects 「風」に処理をしたい。

考えないこと

型安全性

ダックタイピング上等、レイトバインディング・リフレクション万歳!の精神。

遅延実行

処理自体の遅延は出来そうだけど、処理が面倒になりそうなので考えない。

処理速度

現状(170820)では、効率の悪い処理をしているがとりあえず置いておく。

モジュール構成案

  • 各種LINQ風メソッドを持つクラス
  • デリゲートとして使うためのクラス群(後述)
  • 補助処理を入れた標準モジュール

VBAに無い要素と代替案

IEnumerableインターフェイス

対象要素が列挙可能かどうかわからないので、とりあえずFor Eachしてみる。

作成するクラスにはVBA.Collectionを内蔵させて、そのイテレータを使ってFor Eachができるようにする。

デリゲート

「実行可能な処理」を示すインターフェイスと、それを実装したクラス群を作成し、そのクラス群を組み合わせて処理を示す形とする。

VBS用配列ラッパークラス

はじめに

VBScriptではVBA.Collectionをインスタンスできないため、複数の要素をまとめて扱うのが少し面倒。

配列を元に、Collection風に使えるVBScript用クラスをざっくり作ってみたのでメモ。

クラス本体

Class ArrayCol
    '内部格納の配列
    Private clsArray 'As Variant
    
    '現在の要素数
    Private UsedCount 'As Long
    
    Private Sub Class_Initialize()
        Call Me.Clear
    End Sub
    
    Public Sub Clear()
        UsedCount = 0
        ReDim clsArray(4)
    End Sub
    
    '配列の下限
    Private Property Get ARRAY_BASE() 'As Long
        ARRAY_BASE = 1
    End Property
    
    '添え字変換
    Private Function UserIndexToRealIndex(Index) 'As Long
        UserIndexToRealIndex = Index - ARRAY_BASE
    End Function
    
    '要素を追加する。
    Public Sub Add(iItem)
        If UBound(clsArray) = UserIndexToRealIndex(UsedCount) Then Call ArrayExpand
        AssignVal clsArray(UsedCount), iItem
        UsedCount = UsedCount + 1
    End Sub
    
    Private Sub ArrayExpand()
        ReDim Preserve clsArray(UBound(clsArray) * 2)
    End Sub
    
    '代入簡略化処理
    Private Sub AssignVal(ByRef o, i)
        If IsObject(i) Then
            Set o = i
        Else
            o = i
        End If
    End Sub
    
    Public Default Property Get Item(ByVal Index) 'As Variant
        AssignVal Item, clsArray(UserIndexToRealIndex(Index))
    End Property
    
    Public Property Let Item(ByVal Index, Value)
        clsArray(UserIndexToRealIndex(Index)) = Value
    End Property
    
    Public Property Set Item(ByVal Index, Value)
        Set clsArray(UserIndexToRealIndex(Index)) = Value
    End Property
    
    Public Property Get Count() 'As Long
        Count = UsedCount
    End Property
    
    Public Sub Remove(ByVal Index)
        Dim i
        For i = UserIndexToRealIndex(Index) To UserIndexToRealIndex(UsedCount - 1)
            AssignVal clsArray(i), clsArray(i + 1)
        Next 'i
        clsArray(UserIndexToRealIndex(UsedCount)) = Empty
        UsedCount = UsedCount - 1
    End Sub
    
    '既存の配列で初期化する。
    Public Sub InitByArray(BaseArray)
        If Not IsArray(BaseArray) Then Err.Raise 5
        
        Me.Clear
        Dim tmp
        For Each tmp In BaseArray
            Me.Add tmp
        Next 'tmp
    End Sub
    
    Public Function ToArray() 'As Variant
        Dim buf:    buf = clsArray
        ReDim Preserve buf(UserIndexToRealIndex(UsedCount))
        ToArray = buf
    End Function
End Class

実装メンバー

Clear

初期化用。

Add

要素を末尾に追加。

Item

添え字で要素を取得。 上記のコードでは添え字は1からはじまる。 範囲外アクセス時の動作は保証しない。

Count

素数。1から数えた場合の数。

Remove

指定された添え字の要素を除去する。 除去したらその分自動で詰める。

InitByArray

指定した配列で初期化する。 適当実装。

ToArray

配列化する。 For Eachの場合や配列そのものが欲しい場合なんかに。

使用例

Option Explicit
Dim myArray 'As ArrayCol
Set myArray = New ArrayCol

With myArray
    .Add 1
    .Add 3.14
    .Add "文字列"
    .Add Now()
    .Add WScript.ScriptFullName
    .Add New ArrayCol
End With    'myArray
MsgBox myArray(1)
Dim buf: buf = ""
Dim tmp
For Each tmp In myArray.ToArray()
    If IsObject(tmp) Then
        buf = buf & TypeName(tmp) & vbCrLf
    Else
        buf = buf & tmp & vbCrLf
    End If
Next 'tmp

MsgBox buf

'Class ArrayCol
'~

ネタのメモ

現状興味があること、書きたいことのメモ(170509更新)。 どの程度形になるか…。

勉強中

ネタ

  • 文字列の中に特定の文字列が何回出現するのかの数え方(Splitと自作関数)
  • PowerShellでのGUIアプリケーションについての個人的感想
  • PowerShellExcelに子フォームを表示する
  • ExcelPowerPointアドインの違いとかについて

考え中・調査中

  • 各ウィンドウに対してユーザーフォームを表示させる
  • VBA構文解析の方法・考え方
  • Excel.Application.OnUndo

自己紹介的なもの

今更ながら初投稿です。

ブログの内容

プログラミング関係の記事がメインになると思います。

Qiitaにも投稿しているので使い分けを迷っていますが、ある程度まとまった内容はQiita、メモ書きなどははてなブログに書いていこうかと考えています。

自分の環境

プログラミング系の職場ではありませんが、業務の一部としてVBAを触る機会があります。

職場の端末からはインターネット接続禁止、会社敷地内への携帯持ち込み非推奨、のためソフト組み込みヘルプや書籍、脳内メモリだけが頼りです。

勉強中(予定)の言語(≒職場で使える言語)