読者です 読者をやめる 読者になる 読者になる

VB.NETでもLenメソッドを・・・

お願い VisualBasic相談室

VB.NET特有*1Microsoft.VisualBasic.Strings.Lenメソッドってありますよね。

Strings.Len メソッド (Microsoft.VisualBasic)

正直弊社はアレは好きになれないんですよね。 説明文が正直意味がよくわかんないし。

文字列内の文字数または変数を格納するために必要な公称バイト数を表す整数を返します。

ってあるんですけど、そもそも文字列内の文字数と変数を格納する公称バイト数を返すメソッドオーバーロードする意味が分からないし、変数を格納するための公称バイト数って何に格納するのかが分かんないし、文字列を何かに格納するにしても文字符号化方式によってバイト数って変わるじゃんって思ってた訳ですよ。 まず16個もオーバーロードするって意味が分からない。

格納先

とりあえず、何に格納するかはっきりさせましょう。 Microsoft.VisualBasic.FileSystem.FilePutメソッドで値をファイルに書き込む時のバイト数らしいです。 こいつもやたらと多重にオーバーロードされてますが、もうゆるしてください。

興味

とりあえず弊社としてはLen()が返すInt32の値が何を意味するのかが非常に気になるのです。

とりあえずLen(Object)以外は下の表にまとめました。

関数 返す値
Len(Boolean) 2(定数)
Len(Byte) 1(定数)
Len(Char) 2(定数)
Len(DateTime) 8(定数)
Len(Decimal) 8(定数)
Len(Double) 8(定数)
Len(Int16) 2(定数)
Len(Int32) 4(定数)
Len(Int64) 8(定数)
Len(SByte) 1(定数)
Len(Single) 4(定数)
Len(String) 引数として与えられた値のLengthプロパティの値
Len(UInt16) 2(定数)
Len(UInt32) 4(定数)
Len(UInt64) 8(定数)

まさかの15個中14個中が定数。 たしかVBではオーバーロード性的静的に決定されるはずですからインライン展開が捗りますね。

そしてLen(String)はなんとString.Lengthを呼び出すというVBにしてはひねりのない結果に。 せっかくだからMicrosoft.VisualBasic.CompilerServices名前空間メソッドとか呼び出せば良かったのに。 (Stringの等値演算子の件をまだ引きずってる)

他のは実際にファイルに書き出す時のバイト数(らしい)のにStringだけ文字数*2ってのはなんと言いますか、ビミョーに一貫性の無いオーバーロードですね。

こんな現実を見せつけられるとLen(Object)もあらゆるオブジェクトに使える万能宝具って訳じゃなさそうです。

Len(Object)

基本的には以下のパターンで長さを求めてるみたいです。

Nothingの場合

0

System.IConvertibleを実装している場合

System.IConvertibleを実装している場合はオブジェクトのGetTypeCode()を呼び出して、EmptyObjectDBNull以外の型だったらそれそれのオーバーロードしているバージョンのLen()が返す値と同じ値を返します。

StringIConvertibleを実装しているので、なんやかんやでString.Lengthの値が返ります。

Charの配列の場合

配列の長さを返します。

上記以外もしくはGetTypeCode()がEmpty、Object、DBNullの場合

よくわかんない。構造体のバイト数?

まとめ

なんかスパッと答えが分からなくてもやもやした結果となりました。 まぁ、ほとんどの場合はLen()は文字列の長さを求める為に用いられていると思いますので、素直にString.Lengthを使いましょう。

こんなにたくさんオーバーロードされたり引数としてObjectを取るバージョンも定義されているのはバリアント型が存在したレガシーVBとの互換性的な何かを求めての事でしょうけど、.NETにおいてここまでレガシーVBを引きずらなくてもいいんじゃないかな〜みたいな。

そういえばFileSystem.FilePutメソッドって文字列はどのエンコードで書き出すのでしょうか。 無難にUTF-8UTF-16かな? ロケールに合わせて変えていたら面白いですね。 気が向いたら調べてみましょう。

おわり

追記

よくよく調べてみたらソースコードが公開されてました。

Reference Source

*1:C#でも使えるが使う意味・理由が無い。

*2:正確には文字数って訳じゃないけど今回は文字コードメインじゃないので