C#プログラミングにおいて、数値型のintと文字列型のstringを相互に変換する操作は、最も頻繁に行われるタスクの一つです。
ユーザー入力を数値として計算に利用したり、計算結果を画面やログに出力したりする際、この変換処理を避けて通ることはできません。
しかし、単純な変換であっても、手法によってパフォーマンスやエラー耐性、さらには可読性が大きく異なります。
最新の.NET環境では、従来の変換方法に加えて、メモリ効率を意識した新しい書き方も定着しています。
本記事では、初学者から実務経験者まで役立つ、C#における数値と文字列の相互変換について、効率的な書き方と実務上の注意点を踏まえて詳しく解説します。
intからstringへ変換する方法
整数を文字列に変換する場面は、主にUIへの表示やデバッグログの出力などで発生します。
C#にはいくつかの方法が用意されていますが、状況に応じて最適なものを選択することが重要です。
ToStringメソッドを利用する
最も基本的かつ一般的な方法が、すべてのオブジェクトが持っているToString()メソッドを呼び出すことです。
int number = 123;
string result = number.ToString();
Console.WriteLine(result);
123
この方法は非常にシンプルで、コードの意図が明確であるというメリットがあります。
また、ToStringメソッドの引数に「書式指定文字列」を渡すことで、ゼロ埋めやカンマ区切りなどのフォーマットを同時に適用することも可能です。
int price = 1500;
// 5桁でゼロ埋め
string formatted1 = price.ToString("D5");
// 3桁区切りのカンマを入れる
string formatted2 = price.ToString("N0");
Console.WriteLine(formatted1);
Console.WriteLine(formatted2);
01500
1,500
文字列補間(String Interpolation)を利用する
C# 6.0以降で広く使われているのが、$""記法を用いた文字列補間です。
変数を直接文字列の中に埋め込むことができるため、複数の値を組み合わせて文章を作る際に非常に便利です。
int age = 25;
string message = $"ユーザーの年齢は {age} 歳です。";
Console.WriteLine(message);
ユーザーの年齢は 25 歳です。
内部的にはstring.Formatに近い処理が行われますが、コンパイラによる最適化が進んでおり、可読性とパフォーマンスのバランスに優れています。
現代のC#開発において、単なる変数変換以上の用途であれば文字列補間が第一選択肢となります。
string.Concat や + 演算子による結合
文字列と数値を+演算子で結合すると、暗黙的にToString()が呼ばれて変換されます。
int score = 100;
string text = "スコア: " + score;
手軽ではありますが、大量のループ内でこれを行うと、不必要な文字列インスタンスが生成され、ガベージコレクション(GC)の負荷を高める原因になります。
パフォーマンスが求められるシーンでは、後述するSpanやStringBuilderの検討が必要です。
stringからintへ変換する方法
文字列を数値に変換する場合、入力データが「必ず数値である」という保証がないことが多いため、例外処理やエラーチェックが極めて重要になります。
int.Parseメソッド
int.Parse()は、引数に渡された文字列を整数に変換します。
string input = "456";
int result = int.Parse(input);
Console.WriteLine(result);
456
ただし、このメソッドには大きなリスクがあります。
引数が数値として解釈できない形式だった場合や、nullだった場合に例外(Exception)をスローする点です。
| 失敗の原因 | 発生する例外 |
|---|---|
| 文字列が数値以外(例: “abc”) | FormatException |
| 数値がintの範囲を超えている | OverflowException |
| 引数がnull | ArgumentNullException |
そのため、int.Parseは「データが数値であることが確実に保証されている内部的な処理」以外では使用を控えるべきです。
int.TryParseメソッド(推奨)
実務で最も推奨されるのがint.TryParse()です。
このメソッドは、変換に失敗しても例外を投げず、bool型の戻り値で成功・失敗を知らせてくれます。
string input = "123a"; // 数値ではない文字が含まれる
if (int.TryParse(input, out int result))
{
Console.WriteLine($"変換成功: {result}");
}
else
{
Console.WriteLine("変換失敗: 数値として正しくありません。");
}
変換失敗: 数値として正しくありません。
out var構文(インライン変数宣言)を使用することで、コードを簡潔に保ちつつ安全な変換が可能です。
ユーザー入力や外部APIからのレスポンスを扱う際は、例外によるアプリケーションの停止を防ぐため、必ずTryParseを選択してください。
Convert.ToInt32メソッド
Convert.ToInt32()もよく使われる手法です。
内部的にはint.Parseを呼び出していますが、大きな違いは引数がnullの場合に0を返すという挙動です。
string input = null;
int result = Convert.ToInt32(input);
Console.WriteLine(result);
0
データベースの値など、nullが含まれる可能性があるデータを簡易的に扱いたい場合に便利ですが、変換失敗時にはやはり例外が発生するため、安全面ではTryParseに劣ります。
2026年における最新の変換テクニック
C#と.NETの進化により、以前よりも高効率な変換手法が登場しています。
特にクラウドネイティブな開発や高頻度なデータ処理においては、これらの手法が標準となりつつあります。
Span を活用した低アロケーションな変換
大量の文字列解析を行う場合、Substringなどで新しい文字列インスタンスを作成するとメモリ効率が悪化します。
ReadOnlySpan<char>を使用することで、メモリをコピーせずに特定の部分を数値としてパースできます。
// "Data:12345" という文字列から数値部分だけをパースしたい場合
string rawData = "Data:12345";
ReadOnlySpan<char> span = rawData.AsSpan();
// 5文字目から最後までをスライス(コピーは発生しない)
ReadOnlySpan<char> numberPart = span.Slice(5);
if (int.TryParse(numberPart, out int value))
{
Console.WriteLine($"パース結果: {value}");
}
現代のC#では、int.TryParseがReadOnlySpan<char>を受け取れるようオーバーロードされているため、これを利用することでヒープメモリの割り当て(Allocation)を劇的に削減できます。
Utf8Parser によるバイナリデータの直接変換
Web APIやネットワーク通信において、UTF-8形式のバイト配列から直接数値を取得したい場合は、System.Buffers.Text.Utf8Parserを利用します。
一度stringにデコードしてからパースする手間を省けるため、非常に高速です。
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes("9876");
if (System.Buffers.Text.Utf8Parser.TryParse(utf8Bytes, out int val, out int bytesConsumed))
{
Console.WriteLine($"バイナリからの変換: {val}");
}
数値変換における注意点とベストプラクティス
変換処理を実装する上で、バグを防ぎ、パフォーマンスを維持するための注意点をまとめます。
ロケール(文化圏)の影響
数値の表記は国や地域によって異なります。
例えば、一部のヨーロッパ諸国ではカンマ,が小数点として使われ、ピリオド.が桁区切りに使われることがあります。
intの場合は小数点の問題はありませんが、桁区切り文字が含まれる文字列をパースする際には、CultureInfoを意識する必要があります。
不特定の環境で動作させるサーバーサイドプログラムなどでは、不変の文化圏(Invariant Culture)を指定するのが安全です。
using System.Globalization;
string input = "1,234";
// 桁区切りを許可してパース
var style = NumberStyles.AllowThousands;
var culture = CultureInfo.InvariantCulture;
if (int.TryParse(input, style, culture, out int result))
{
// InvariantCultureではカンマは通常パースされない設定が多いが、
// 明示的に指定することで意図しない挙動を防げる
}
変換のオーバーヘッド
単純なアプリケーションでは気にする必要はありませんが、1秒間に数百万回の変換を行うようなバッチ処理やゲーム開発、高負荷なマイクロサービスでは、ToStringが生成する新しい文字列がGCのトリガーとなり、パフォーマンス低下を招くことがあります。
このような場合は以下の対策を検討してください。
- 補間文字列のリテラル化:固定の文字列なら定数化する。
- ISpanFormattableの活用:スタックメモリ上の
Spanに直接書き込む。 - 値のキャッシング:頻出する数値(0や1など)の文字列をあらかじめ保持しておく。
nullの取り扱い
C# 8.0以降のnull許容参照型の導入により、string?型を扱う機会が増えました。
変換元がnullである可能性をコンパイラが警告してくれるため、これを無視せずに適切にハンドリングすることが、堅牢なコードへの近道です。
string? userInput = GetInput();
// userInputがnullの場合、int.ParseはArgumentNullExceptionを投げる
// TryParseならfalseを返すだけで済む
if (int.TryParse(userInput, out int result))
{
// 処理
}
まとめ
C#におけるintとstringの変換は、言語の基本でありながら、奥が深いトピックです。
- 数値から文字列への変換は、単純な場合は
ToString()、文章に組み込む場合は$""(文字列補間)が最適です。 - 文字列から数値への変換は、例外を避けるために原則として int.TryParse() を使用してください。
- 大量のデータを扱う現代の開発では、
ReadOnlySpan<char>を活用して、メモリ効率を最大化する書き方が推奨されます。 - グローバルな実行環境を想定する場合、
CultureInfo.InvariantCultureの使用を検討し、予期せぬパースエラーを防ぎましょう。
これらの手法を適切に使い分けることで、バグが少なく、かつ高速に動作するアプリケーションを構築することができます。
日々のコーディングの中で「この変換に例外のリスクはないか?」「この書き方でメモリを無駄に消費していないか?」を意識する癖をつけることが、エンジニアとしてのスキルアップに繋がります。
