演習 - データ型のキャストと変換を調べる
データ型の変換にはさまざまな手法があります。 選択する手法は、次の 2 つの重要な質問に対する答えによって異なります。
- 値によっては、値のデータ型を変更しようとしたとき、実行時に例外がスローされることがありますか。
- 値によっては、値のデータ型を変更しようとしたとき、情報が失われることがありますか。
この演習では、これらの質問、その答えの意味、データ型を変更する必要があるときに使用すべき手法について段階的に考察していきます。
コーディング環境を準備する
このモジュールには、デモ コードをビルドして実行するプロセスをガイドする実践的なアクティビティが含まれています。 これらのアクティビティを完了するために、開発環境として Visual Studio Code を使用することをお勧めします。 これらのアクティビティに Visual Studio Code を使用すると、世界中のプロフェッショナルが使用する開発環境でコードの記述と実行をより快適に行うことができます。
Note
この C# シリーズの Microsoft Learn を完了している場合は、コード サンプル用のプロジェクト フォルダーが既に作成されている場合があります。 その場合は、手順の次のセクションをスキップし、前の演習で使用した Project.cs
ファイル内のコードを削除できます。
Visual Studio Code を開きます。
Visual Studio Code は、Windows の [スタート] メニュー (別の OS の場合は同等のリソース) を使用して開くことができます。
Visual Studio Code の [ファイル] メニューで、[フォルダーを開く] を選択します。
[フォルダーを開く] ダイアログで、Windows の [デスクトップ] フォルダーに移動します。
コード プロジェクトを保持するフォルダーの場所が異なる場合は、代わりにそのフォルダーの場所を使用できます。 このトレーニングでは、見つけやすく覚えやすい場所を用意することが重要です。
[フォルダーを開く] ダイアログで、[フォルダーの選択] を選択します。
作成者を信頼するかどうかを確認するセキュリティ ダイアログが表示された場合は、[はい] を選択します。
Visual Studio Code の [ターミナル] メニューで、[新しいターミナル] を選択します。
[ターミナル] パネルのコマンド プロンプトに、現在のフォルダーのフォルダー パスが表示されることを確認します。 次に例を示します。
C:\Users\someuser\Desktop>
指定したフォルダーに新しいコンソール アプリケーションを作成するには、ターミナルのコマンド プロンプトで「
dotnet new console -o ./CsharpProjects/TestProject
」と入力し、Enter キーを押します。この .NET CLI コマンドでは、.NET プログラム テンプレートを使用して、指定したフォルダーの場所に新しい C# コンソール アプリケーション プロジェクトを作成します。 このコマンドで [CsharpProjects] と [TestProject] のフォルダーが自動的に作成され、
.csproj
ファイルの名前として TestProject が使用されます。[エクスプローラー] パネルで、[CsharpProjects] フォルダーを展開します。
[TestProject] フォルダーと、Program.cs という名前の C# プログラム ファイルと、TestProject.csproj という名前の C# プロジェクト ファイルの 2 つが表示されるはずです。
[エクスプローラー] パネルの [エディター] パネルにコード ファイルを表示するには、[Program.cs] を選択します。
既存のコード行を削除します。
このモジュールでは、この C# コンソール プロジェクトを使用して、コード サンプルを作成およびビルドして実行します。
[ターミナル] パネルを閉じます。
質問: 値のデータ型を変更すると、実行時に例外がスローされる可能性はありますか?
C# コンパイラはコードに対応しようとしますが、例外を生成する可能性のある演算はコンパイルされません。 C# コンパイラの主な懸念事項を理解すれば、コンパイラが特定の方法で機能する理由を簡単に理解できます。
int
への int
と string
の追加と結果の保存を試行するコードを記述する
Visual Studio Code が開いていて、[エディター] パネルに Program.cs が表示されていることを確かめます。
Note
Program.cs は空になっているはずです。 そうでない場合は、すべてのコード行を選択して削除します。
Visual Studio Code エディターに次のコードを入力します。
int first = 2; string second = "4"; int result = first + second; Console.WriteLine(result);
ここでは、値
2
と4
を加算しようとしています。 値4
はstring
型です。 これは動作しますか。Visual Studio Code の [ファイル] メニューで、[保存] を選択します。
コードをビルドまたは実行する前に、Program.cs ファイルを保存する必要があります。
[エクスプローラー] パネルで、TestProject フォルダーの場所にあるターミナルを開くには、TestProject を右クリックし、[統合ターミナルで開く] を選択します。
ターミナル パネルが開き、ターミナルが TestProject フォルダーの場所に対して開かれていることを示すコマンド プロンプトが表示されます。
コードを実行するには、ターミナルのコマンド プロンプトで、「
dotnet run
」と入力し、Enter キーを押します。次のような出力が表示されます
C:\Users\someuser\Desktop\csharpprojects\TestProject\Program.cs(3,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
Note
"実行するプロジェクトが見つかりませんでした" というメッセージが表示された場合は、ターミナルのコマンド プロンプトに、予期されている TestProject フォルダーの場所が表示されていることを確かめます。 例:
C:\Users\someuser\Desktop\csharpprojects\TestProject>
ここで、コンパイラが最初のコード サンプルを実行できなかった理由を少し考えてみましょう。
エラー メッセージの重要な部分 (
(3,14): error CS0029: Cannot implicitly convert type 'string' to 'int'
) は、string
データ型の使用に問題があることを示しています。しかし、C# コンパイラがエラーを処理できないのはなぜでしょうか? 結局、"逆のこと" を行えば、数値を
string
に連結し、それを文字列変数に保存できます。 ここで、result
変数のデータ型をint
からstring
に変更します。Visual Studio Code エディターでコードを次のように更新します。
int first = 2; string second = "4"; string result = first + second; Console.WriteLine(result);
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次のような出力が表示されます。
24
この出力は数学的には正しいものではなく、値は文字 "2" と "4" の組み合わせとして出力されています。
result
変数の型がint
である最初のコード例をもう一度見てみましょう。 このコードには、エラー メッセージが含まれています。int first = 2; string second = "4"; int result = first + second; Console.WriteLine(result);
4
を含む変数second
をstring
ではなく数値として処理する必要があることを C# コンパイラが理解できないのはなぜでしょうか?
コンパイラは安全な変換を行う
C# コンパイラでは、潜在的な問題が進行していることが認識されています。 変数 second
は string
型であり、"hello"
のような別の値に設定される場合があります。 C# コンパイラで "hello"
を数値に変換しようとすると、実行時に例外が引き起こされることがあります。 この可能性を回避するために、C# コンパイラでは、string
から int
への暗黙的な変換は自動的に実行されません。
C# コンパイラの視点では、安全な演算は、int
を string
に変換し、連結を実行することです。
文字列を使用して加算することが意図であれば、C# コンパイラでは、データ変換のプロセスをもっと明示的に制御する必要があります。 言い換えると、変換によって例外がスローされる可能性に対処するため、ユーザーが適切な予防対策をとれるよう、ユーザーにさらなる関与が強いられます。
元のデータ型から新しいデータ型に値を変更する必要があるとき、実行時、その変更から例外が発生する可能性があるとき、データを変換する必要があります。
データを変換する目的で、次のいずれかの手法を利用できます。
- データ型でヘルパー メソッドを使用する
- 変数でヘルパー メソッドを使用する
Convert
クラスのメソッドを使用する
このユニットで後ほど、これらのデータ変換手法の例をいくつか示します。
質問: 値のデータ型を変更すると、情報が失われる可能性はありますか?
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。int myInt = 3; Console.WriteLine($"int: {myInt}"); decimal myDecimal = myInt; Console.WriteLine($"decimal: {myDecimal}");
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次の出力が表示されます。
int: 3 decimal: 3
このサンプルの鍵となるのが次のコード行です。
decimal myDecimal = myInt;
int
値はdecimal
の内部に簡単に収まるため、コンパイラで変換が実行されます。"拡大変換" という言葉は、"より少ない" 情報を保持できるデータ型から "より多い" 情報を保持できるデータに値を変換しようとすることを意味します。 この場合、
int
型の変数に格納されている値はdecimal
型の変数に変換され、情報は失われません。拡大変換が実行されることがわかっている場合は、暗黙的な変換を使用できます。 コンパイラによって暗黙的な変換が処理されます。
キャストを実行する
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。decimal myDecimal = 3.14m; Console.WriteLine($"decimal: {myDecimal}"); int myInt = (int)myDecimal; Console.WriteLine($"int: {myInt}");
キャストを実行するには、キャスト演算子
()
を使用してデータ型を囲み、変換する変数の隣に配置します (例:(int)myDecimal
)。 定義されたキャスト データ型 (int
) への明示的な変換を実行します。コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次の出力が表示されます。
decimal: 3.14 int: 3
このサンプルの鍵となるのが次のコード行です。
int myInt = (int)myDecimal;
変数
myDecimal
には、小数点以下の有効桁数を持つ値が保持されます。 キャスト命令(int)
を追加することで、その有効桁数が失われる可能性があることを認識しているが、この場合は問題ないことを C# コンパイラに伝えます。 意図的な変換 (明示的な変換) を実行することをコンパイラに伝えます。
変換が "拡大変換" であるか、または "縮小変換" であるかを判断する
縮小変換という用語は、"より多い" 情報を保持できるデータ型からより少ない情報を保持できるデータに値を変換することを意味します。 この場合、精度 (つまり、小数点以下の値) などの情報が失われることがあります。 たとえば、decimal
型の変数に格納されている値を型 int
の変数に変換する場合です。 2 つの値を出力すると、情報が失われていることに気付くでしょう。
縮小変換が実行されることがわかっている場合は、キャストを実行する必要があります。 キャストでは、精度が失われる可能性があることをユーザーは理解しており、それを受け入れるということが C# コンパイラに指示されます。
変換でデータが失われるかどうかがわからない場合は、2 つの異なる方法で変換を実行するコードを作成して、変化を観察します。 開発者は多くの場合、動作をより詳細に理解できるように、次のサンプルで示すような小さなテストを作成します。
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。decimal myDecimal = 1.23456789m; float myFloat = (float)myDecimal; Console.WriteLine($"Decimal: {myDecimal}"); Console.WriteLine($"Float : {myFloat}");
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次の出力が表示されます。
Decimal: 1.23456789 Float: 1.234568
この出力から、
decimal
をfloat
にキャストすると有効桁数が失われるため、縮小変換であることがわかります。
データを変換する
前に、あるデータ型から別のデータ型に値を変更すると実行時例外が発生する可能性があるため、データ変換を実行する必要があると説明しました。 データ変換には、次の 3 つの手法を使用できます。
- 変数でヘルパー メソッドを使用する
- データ型でヘルパー メソッドを使用する
Convert
クラスのメソッドを使用する
ToString()
を使用して数値を string
に変換する
すべてのデータ型変数に ToString()
メソッドがあります。 ToString()
メソッドの動作は、特定の型におけるその実装方法に依存します。 ただし、ほとんどのプリミティブでは、拡大変換が実行されます。 (ほとんどの場合、暗黙的な変換を使用できるため) これは厳密に必須ではありませんが、自分が何を実行しているかを理解していること、それが意図的なものであることを他の開発者に伝えることができます。
次は、ToString()
メソッドを利用し、int
値を string
に明示的に変換する簡単な例です。
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。int first = 5; int second = 7; string message = first.ToString() + second.ToString(); Console.WriteLine(message);
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。 コードを実行すると、出力に次の 2 つの値の連結が表示されます。
57
Parse()
ヘルパー メソッドを使用して string
を int
に変換する
ほとんどの数値データ型には Parse()
メソッドがあります。これは、文字列を特定のデータ型に変換します。 この場合、Parse()
メソッドを使用して 2 つの文字列を int
値に変換し、それらを加算します。
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。string first = "5"; string second = "7"; int sum = int.Parse(first) + int.Parse(second); Console.WriteLine(sum);
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。 コードを実行すると、出力には次のような 2 つの値の和が表示されるはずです。
12
ここで少し時間を取って、前のコード例で潜在的な問題を見つけてみることにしましょう。
int
に変換できない値に変数first
またはsecond
が設定されている場合、どうなりますか。 実行時に例外がスローされます。 C# コンパイラとランタイムでは、ユーザーが事前に計画して、"不正な" 変換を防ぐと想定しています。 ランタイム例外は、いくつかの方法で軽減できます。この状況を最も簡単に軽減するには、
TryParse()
を使用します。これは、Parse()
メソッドの改良版です。
Convert
クラスを使用して string
を int
に変換する
Convert
クラスには、値の型を変換できる多くのヘルパー メソッドがあります。 次のコード例では、いくつかの文字列を int
型の値に変換します。
Note
この演習のコード サンプルは、米国 (en-US) のカルチャ設定に基づいて設計されており、小数点の記号としてピリオド (.
) を使用します。 別の小数点 (コンマ ,
など) を使用するカルチャ設定でコードをビルドして実行すると、予期しない結果やエラーが発生する可能性があります。 この問題を修正するには、コード サンプルの小数点のピリオドをお使いのローカルの小数点 (,
など) に置き換えます。
または "en-US" のカルチャ設定を使用してプログラムを実行したい場合は、次のコードをプログラム using System.Globalization;
の先頭に追加し、他のすべての using
ステートメントの後に CultureInfo.CurrentCulture = new CultureInfo("en-US");
を追加します。
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。string value1 = "5"; string value2 = "7"; int result = Convert.ToInt32(value1) * Convert.ToInt32(value2); Console.WriteLine(result);
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次の出力が表示されます。
35
Note
メソッド名はなぜ
ToInt32()
ですか。 なぜToInt()
ではないのでしょうか。System.Int32
は .NET クラス ライブラリにおける基礎的なデータ型の名前であり、C# プログラミング言語ではint
というキーワードに相当します。Convert
クラスは .NET クラス ライブラリの一部でもあるため、その C# 名ではなく、そのフルネームで呼ばれています。 .NET クラス ライブラリの一部としてデータ型を定義することで、Visual Basic、F#、IronPython など、さまざまな .NET 言語で .NET クラス ライブラリと同じデータ型と同じクラスを共有できます。ToInt32()
メソッドには 19 個のオーバーロード バージョンがあり、事実上あらゆるデータ型に対応できます。ここでは、文字列で
Convert.ToInt32()
メソッドを使用しましたが、可能な場合は、おそらくTryParse()
を使用する必要があるでしょう。では、
Convert
クラスを使用する必要があるのは、どんな場合でしょうか?Convert
クラスは分数を整数 (int
) に変換する場合に最適です。予想どおりに丸められるからです。
decimal
から int
へのキャストと変換を比較する
次の例では、decimal
を int
にキャストする場合 (縮小変換) と Convert.ToInt32()
メソッドを利用して同じ decimal
を int
に変換する場合の違いを確認できます。
前の演習手順のコードを削除するか、行コメント演算子
//
を使用してコメントにし、次のコードを追加します。int value = (int)1.5m; // casting truncates Console.WriteLine(value); int value2 = Convert.ToInt32(1.5m); // converting rounds up Console.WriteLine(value2);
コード ファイルを保存し、Visual Studio Code を使用してコードを実行します。
次の出力が表示されます。
1 2
キャストは切り捨て、変換は丸め
int value = (int)1.5m;
をキャストすると、浮動小数点数の値は切り捨てられるため、結果は 1
になります。つまり、小数点以下の値は完全に無視されます。 リテラル浮動小数点数を 1.999m
に変更すると、キャストの結果は同じになります。
Convert.ToInt32()
を使用して変換すると、リテラル浮動小数点数の値は 2
に正しく丸められます。 リテラル値を 1.499m
に変更すると、1
に丸められます。
要点
データの変換とキャストの重要な概念をいくつか取り上げました。
- データ変換の実行中にランタイム エラーが発生しないようにする
- 明示的なキャストを実行して、データ損失のリスクを理解していることをコンパイラに伝える
- 拡大変換を実行する場合、暗黙的なキャストの実行をコンパイラにまかせる
- キャスト演算子
(int)myDecimal
とデータ型を使用してキャストを実行する (例:()
) - 縮小変換を実行するが、情報を切り捨てずに丸める場合、
Convert
クラスを使用する