こんにちは、働くC#プログラマーのさんさめです。
開発されてから長期間保守されている
アプリケーションのソースコードには、
当時の仕様で書かれているコードが一定数存在します。
- async/awaitがない頃の非同期処理
- null条件演算子がない頃のnullチェック
- 出力変数宣言がない頃の出力引数の宣言
- etc…
上に挙げたものでも色々語れてしまいますが、
今回は割愛します。
そのような旧仕様の中でも、
string.Formatメソッドは大変問題があるので、
積極的に置き換えていくことをおススメします。
本記事では、string.Formatの問題点と、
C#6.0で追加された代替機能である文字列補間($””)の解説をします。
string.Formatとは
string.Formatは
文字列リテラルと、変数や式の値を混合させた、
新しい文字列を作りたいときに使用するメソッドです。
例えば以下のように使います。
var intValue = 42;
var str = string.Format("{0}を2倍した数は{1}です",
intValue,
intValue * 2);
Console.WriteLine(str); // 42を2倍した数は84です
{0}や{1}と書いた部分が、インデックスを表しており、
そのあとに続けた引数に置き換わります。
C言語を勉強したことある人は
ピンとくるかもしれませんが、
これはprintf関数の呼び出し方にどことなく似ています。
そのため、
CからC#に移った人は特に違和感なく使いがちです。
使いがち、というか昔はこれしかなかったのですが。
しかしながら、前述したように
C#6.0以降であれば、文字列補間を使った方が、
すっきり明解、かつ問題も起きにくいと良いことづくめになります。
文字列補間とは
文字列補間とは、C#6.0で追加された、
string.Formatと同様のことができる記法です。
先ほどのサンプルコードを文字列補間による記法で
置き換えてみます。
var intValue = 42;
var str = $"{intValue}を2倍した数は{intValue * 2}です";
Console.WriteLine(str); // 42を2倍した数は84です
文字列補間の記法は
文字列リテラルを表す””の前に「$」を入力する
というものになります。
そして、””で括った部分に波括弧「{}」を入力すると、
括弧内は式として認識されます。
どうでしょうか。
既にstring.Formatの時よりも
格段に読みやすいですね。
また、文字列補間で記述した場合には
ハイライトもちゃんと付くため、
読みやすさには歴然の差がでてきます。
string.Formatの問題点と文字列補間での改善点
さて、読みやすさの面だけでなく、
string.Formatにはいくつか問題点があります。
- タイピング量が多い
- 文字列と引数の関係性が分かりにくい
- 使い方を間違えても実行してみるまで気づけない
そして、文字列補間による記法では、
これらすべてを改善しています。
ひとつずつ見ていきましょう。
string.Formatの問題点1:タイピング量が多い
1つ目の問題点はシンプルで、
「タイピング量が多い」
ことです。
「string.Format」と打つだけでも大変なのに、
「()」も必要ですし、引数が多ければ「,」も
つどつど入力しなければいけません。
タイピング量が多いということは文字数も多いので、
読む人の負担にもなります。
文字列補間の書き方であれば、
「$」を先頭につけるくらいで済みます。
また、記法を知らない人が読んだとしても、
文脈で理解できる範疇です。
string.Formatの問題点2:文字列と引数の関係性が分かりにくい
2つ目の問題点は、
「文字列と引数の関係性が分かりにくい」
という点です。
もう一度string.Formatのコードを見てみましょう。
var str = string.Format("{0}を2倍した数は{1}です",
intValue,
intValue * 2);
{0}や{1}と、intValueやintValue * 2の部分の対応を把握するのに、
少し時間がかかりますよね。
え、そうでもないですか?
では以下ならどうでしょう。
var str = string.Format("{2}を2倍した数は{0}ですが、{1}と{2}を足すと{3}になります",
intValue * 2,
4,
intValue,
intValue + 4);
ぎゃあああああ!
インデックスの登場順序をバラバラにした上に、
{2}を2回使ってみました。
さすがにこれは極端な例ですが、
こういうことも書けてしまうわけです。
文字列補間の書き方であれば、
この極端な例も以下の通りです。
$"{intValue}を2倍した数は{intValue * 2}ですが、{4}と{intValue}を足すと{intValue + 4}になります";
少し横に長くなりはしましたが、
非常に分かりやすいですね。
このページで使用しているコードハイライトの性能がイマイチですが、
VisualStudioならこの通りです。
うむ、。安心する~
string.Formatの問題点3:使い方を間違えても実行してみるまで気づけない
さて、最初のサンプルを少しいじって、
以下のように書き換えたとしましょう。
var str = string.Format("{0}を2倍した数は{1}です",
intValue);
何か足りてませんね。
{1}を指定しているにも関わらず、
そのあとの引数が1つしかありません。
でもこれ、実はビルドは成功するんです。
そして、該当箇所を実行しようとしたときに、
例外になります。
これが3つ目の問題点です。
できればコンパイル時にエラーになってほしいですね。
もし、テスト不足などで
ユーザーにリリースしてから初めて発覚…
とかなったらとっても悲惨です。
文字列補間ではこのようなことはありません。
例えば以下の書き方をしたら、
しっかりコンパイルエラーになります。
$"{intValue}を2倍した数は{}です";
// ↑中括弧記述しているのに式がないのでエラー
間違った記述に早めに気づけることで、
ユーザーに不利益を被らせにくくなりますね。
ちなみに、VisualStudio 2019では、
string.Formatの引数不足に対して、
テキストエディタ上で警告を出してくれるようになっています。
賢い。 残念ながらビルドは通ってしまいますが…
さんさめは文字列補間を積極的におススメします
string.Formatの3つの問題点を挙げて、
文字列補間の優位性を解説しました。
さんさめ自身も昔はstring.Formatを使っていましたが、
やはり書きづらいし読みづらいしでつらかったですね。
今ではstring.Formatは全く使っていません。
文字列補間でサクサクコーディングしています。
というか、string.Formatは
潜在的に実行時エラーの可能性も含んでいるため、
見かけ次第置き換えています。
非常におススメです。
ぜひ置き換えていきましょう。
まとめ
まとめです。
- string.Formatは文字列生成に便利だが問題点が多い
- 文字列補間による記法は以下の点で
string.Formatの上位互換- 記述しやすい
- 処理内容を理解しやすい
- 間違いに早めに気づける
- 既存コードも文字列補間に置き換えていくことを
おススメしています
最後までお読みいただきありがとうございました。
コメント