メソッドチェーンが使える String クラスを作る

# メソッドチェーンが使える String クラスを作る

## 経緯

VBAのショボい点として、String 型でメソッドチェーンが使えない点がある。
メソッドチェーンというのは xxx.Trim.SubString(0,1) のようにメソッドを続けて使える機能。
メソッドチェーンにするためには、クラスを返却するメソッドを作ればいいが、String型も同時に返したい。そんな不可能？と思われたが、試行錯誤してみたところ、実用になるレベルになったのでやりかたを紹介する。


使い勝手は以下のようになる。メソッドをいくらでもつなげて使えるし、メソッドの戻り値を**String型と同等の動作** にすることができる。

```vb
Sub StringEx_Sample()

    Dim s As IString
    Set s = New StringEx
    
    '普通にStringっぽく使える
    s = "abcdefg  "
    Debug.Print s
    Debug.Print s & "desu"

    'Java/C# のようなメソッドチェーンも使える
    Debug.Print s.SubString(2, 4)
    Debug.Print s.SubString(2, 4).Length

    Debug.Print s.Length
    Debug.Print s.Trim.Length

End Sub

-----------------------
abcdefg  
abcdefg  desu
cd
 2 
 9 
 7 
```
ソース入力時にインテリセンスももちろん使える。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/69810/206a2079-c040-8840-bb72-11611bc01820.png)

## ソース解説

やること。

・String 型を返すメソッドは IString インタフェースを返すようにする。
　→これでメソッドチェーンを実現する。

・IString インタフェースにString型の規定のプロパティを作り、メソッドを省略した場合、String 型を返すようにする。
　→クラスでありながら、String 型としても扱えるようになる。

### IString インターフェース

インターフェースを使用しなくても作れるけど、好きなので。

文字列を保持するためのプロパティ「Value」を定義する。
Value プロパティを規定のプロパティにすると、省略可能になります。

規定のプロパティを作成するためには以下の手順が必要となります。

* クラスをエクスポートする。
* エディタ等でクラスを編集し、プロパティプロシージャ（LetやGetのどちらか１つ）の中に「Attribute Item.VB_UserMemId = 0」を追加する。
* VBEでインポートしなおす。

これはインターフェース側に指定しておけば、Impliments した方でも有効になる。
インターフェースを使用しない場合は、StringEx 側の Value プロパティに上記の設定を行ってください。

```vb
Option Explicit

Public Function SubString(ByVal starts As Long, Optional ByVal ends As Long = -1) As IString
End Function
Public Property Get Value() As String
    'Attribute Item.VB_UserMemId = 0
End Property
Public Property Let Value(v As String)
End Property
Public Property Get Length() As Long
End Property
Public Function Trim() As IString
End Function
```
### StringEx クラス

メソッドチェーンにしたい場合、編集した結果をNewInstance メソッドで新しいインスタンスのStringExクラスを戻すようにする。(SubStringメソッド、Trimメソッドを参考）

このクラスをフォームと同じように、静的クラス（規定のインスタンス）で使えるようにする。
手順は以下の通り。

* クラスをエクスポートする。
* ソースのプロパティ「Attribute VB_PredeclaredId = False」をエディタ等で「True」に書き換える。
* VBEでインポートしなおす。

StringEx.NewInstance() というコンストラクタが使えるようになる。

```vb
Option Explicit

Implements IString
Private mBuf As String

Public Function NewInstance(ByVal s As String) As IString

    Set NewInstance = New StringEx
    NewInstance.Value = s

End Function

Private Property Get IString_Length() As Long
    IString_Length = Len(mBuf)
End Property

Private Function IString_SubString(ByVal starts As Long, Optional ByVal ends As Long = -1) As IString
    If ends = -1 Then
        Set IString_SubString = Me.NewInstance(Mid$(mBuf, starts + 1))
    Else
        Set IString_SubString = Me.NewInstance(Mid$(mBuf, starts + 1, ends - starts))
    End If
End Function

Private Function IString_Trim() As IString
    Set IString_Trim = Me.NewInstance(Trim(mBuf))
End Function

Private Property Let IString_Value(RHS As String)
    mBuf = RHS
End Property
Private Property Get IString_Value() As String
    IString_Value = mBuf
End Property

```

自分で作ったライブラリの String 型の戻り値を この例を元に IString インターフェースを戻せば便利に使えると思う。

---

フリーソフトを作っています。
Excelを便利にする250以上の機能を体系化したアドインはこちらです。
「RelaxTools Addin」窓の杜大賞受賞ソフト
http://software.opensquare.net/relaxtools/