こんにちは、働くC#プログラマーのさんさめです。
突然ですが、
このようなMessageBoxを出したいと
思ったことはありませんか?
複数のデータを削除するボタンなどを実装したときに、
最終確認として表示する確認ダイアログです。
この時、地味に面倒なのが、
リストの各データの名前を1つの文字列に結合することです。
この手の処理で最初に考え付くのは、
まずstringやStringBuilderの変数を1つ用意して、
リストをforeachで回して文字列に足していく…。
といったものではないでしょうか。
var message = string.Empty;
foreach (var item in list)
{
var label = item.Name + item.Id.ToString();
message += $"{label}\n";
}
MessageBox.Show(message);
でも、これって煩わしいことが沢山ありますよね。
- たかが文字列結合の割にコードの行数が多くなる
- 改行が最後の文字列の後にも入ってしまうのが気になる
- 大量の場合は途中で打ち切りたいが、
そのためには数を数えなければ…
意外と考えること多いな…
実は、こういう時に使える、
string.Joinというメソッドが、
組み込みのメソッドとしてあるんです。
本記事では冒頭の削除確認ダイアログのような
複数行出力の事例を通して、
string.Joinのよくある使い方を紹介します。
string.Joinは文字列リストを連結するメソッド
改めての紹介になりますが、
string.Joinは、
「指定したリスト」を「指定した文字列」で、
連結して1つのstringを返す、
組み込みの静的メソッドです。
組み込みなので、
特定のライブラリをusingしたりすることなく、
すぐに使えます。
以下は冒頭のコードを、
string.Joinを使って書いたサンプルコードです。
var message = string.Join("\n", list.Select(x => x.Name + x.Id.ToString()));
MessageBox.Show(message);
なんと、文字列を連結する部分のコードが
1行になってしまいました。
代わりに1行でやってることが複数になってしまったので、
大きく2つに分解して見ていきます。
まず、最初のところですね。
string.Join("\n", ~~~
ここは、区切り文字を指定しています。
文字列(string)で指定することも、
文字(char)で指定することもできます。
私はダブルクォーテーション(”)の方が打ちやすいので、
特に考えずに文字列で指定することが多いです。
次に、この部分です。
~~~ , list.Select(x => x.Name + x.Id.ToString());
ここでは、LINQのSelectメソッドを使って、
リストの個々の要素を文字列に変換しています。
LINQは便利です。使わないと勿体ない。
…ちょっと話が逸れましたが、
これだけです。超簡単ですね。
慣れるまではその都度調べて思い出しながら
書くことになるかとは思いますが、
慣れてスラスラ書けるようになると快適ですよ。
foreachと違って最後に余計な文字が入らない
結構重要ポイントなのですが、
string.Joinは「リストを指定文字列で結合」
するメソッドなので、
当然、要素と要素の間にしか指定文字列は入りません。
つまり、こういうことです。
実行結果もついでに見てみましょうか。
foreachだと最後に余計なカンマが
おまけでついてきちゃいますが、
string.Joinはそういうことはありません。
スマートです。
途中の切り上げもLINQと組み合わせれば簡単
最初の例に見せたMessageBoxですが、
大量にデータを選択されてしまったときなどは、
MessageBoxが縦長になりすぎる恐れがあります。
そのため、適当な数で切り上げて、
「他〇〇個のファイル」
といった表示に切り替えてあげるのが親切です。
そんな時はLINQのTakeが役に立ちます。
以下はサンプルコードです。
var list = Enumerable.Range(0, 1000)
.Select(x => Path.GetRandomFileName())
.ToArray();
var message = string.Join("\n", list.Take(10));
if (list.Length > 10)
{
message += $"\n他{list.Length - 10}個のデータ";
}
少し長くなりましたが、
1つ1つを見れば
何をやっているかが見えてきます。
重要なのは、
list.Take(displayMaxNum)
のところです。
Takeメソッドを使って、最初の10個だけを取り出し、
それを表示用のメッセージとして、
string.Joinで結合しています。
(もちろん、10個に満たない場合は、
存在する分だけ結合されます)
次に、if文とその中身ですね。
if (list.Length > 10)
{
message += $"\n他{list.Length - 10}個のデータ";
}
10個を超えた場合のみ
あと何個あるのかを追加のメッセージとして含めています。
実行結果は次のような感じです。
良い感じですね。
同じことをforeachのやり方でやろうとすると、
数を数えあげるために、forに書き直したり、
break文が必要になったり、
かなりややこしい記述が必要になります。
1回書く分には全然なんとでもなるのですが、
保守性はかなり下がります…。
string.Joinを使った方が、
やりたいことに対してシンプルに書けるという紹介でした。
まとめ
まとめです。
- 複数のデータを1つの文字列にして出力するのは
意外と面倒な処理 - string.Joinは文字列を結合するメソッドで、
そういうケースに威力を発揮 - 元が独自クラスのリストなら、
Selectと組み合わせると強力 - 途中で切り上げるならTakeを活用する
最後までお読みいただき、ありがとうございました。
関連記事
独自クラスを文字列に加工する時、
string.Formatとか使ってるコードは現存していますか?
文字列補間の書き方に置換した方が読みやすく
例外も起きにくいのでおススメです。
コメント