.NETの文字列(Stringオブジェクト)の単位は,MSDNドキュメントによると,文字数である。つまり,いわゆる半角文字でも全角文字でも,1文字として扱う。だが合成文字は,画面上は1文字として表示されても,Lengthプロパティの値は2になる。さらに,1文字を4バイトで表現するときに使う拡張コード「サロゲート・ペア」を用いる文字(UTF16で4バイト)も,Lengthプロパティの値は2になる。

 ここで,MSDNドキュメントをもう一度調べてみた。String.Lengthプロパティからは,確かに「このインスタンスの文字数を取得」できるとある。だが,解説欄には,「このインスタンス内のCharオブジェクトの数を返します。Unicode文字の数ではありません。これは,1つの Unicode文字が複数のCharで表されることがあるためです」とある。つまり,String.Lengthプロパティからは,文字数が得られるのではなく,UTF16エンコーディング時のワード数が得られるのだった。

 実はこの仕様を決めるときに,マイクロソフト内でも長い間議論があったそうだ。.NETに閉じた世界に限定すれば,完全な文字単位で管理できそうだが,いろいろな場面を想定し,サロゲート・ペアの存在を意識していないアプリケーション・プログラムがクラッシュする可能性を最低にするために,現在の仕様のように合成文字やサロゲート・ペアについて「何もしない」ことが最善であると結論付けられたそうだ。ただ,Unicodeの合成文字やサロゲート・ペアは,今までは入力される機会がほとんど無かったから,意識しなくても問題が起こらなかっただけかもしれない。今後は意識してコーディングする必要がありそうだ。