整数型からメソッドを呼ぶ
C#にも、もちろん、普通のプログラム言語にあるような、整数型や、実数型が存在する。例えば、intという名前のデータ型が、整数型を意味するのは、C/C++/Javaなどと同じである。Visual BasicならInteger(あるいはLong)に相当するものである。その点で、見た目はそれほど飛躍していないように見える。
ところが、実は、intと言うのは世を忍ぶ仮の姿なのである。intは、別名、System.Int32とも呼ばれる。実際に、.NET Frameworkのリファレンス・マニュアルで、SystemネームスペースのInt32という項目を引くと、intから利用できる機能がずらずらと並んでいることが分かるだろう。これらは、int型の数値や変数に対して適用することができる。例えば、文字列に変換するメソッドとして、ToString( )というものがある。整数の123を文字列に変換する場合は「123.ToString( )」という式を書くことができる。整数型の変数iを文字列に変換するのなら、「i.ToString( )」となる。このように、整数のようなシンプルなデータ型に対してメソッドなどを使用できるプログラム言語は多くない。少なくともパソコン上でよく見かけるC++やJavaでは実現できない構文である。
では、本当にi.ToString( )という構文が機能することを、実際のサンプルコードで確かめてみよう。
1: namespace ConsoleApplication6
2: {
3: using System;
4:
5: public class Class1
6: {
7: public static int Main(string[] args)
8: {
9: int i=123;
10: string s = i.ToString();
11: Console.WriteLine( "i={0}, s={1}", i, s );
12: return 0;
13: }
14: }
15: } |
|
整数型変数を文字列に変換するi.ToString( )のサンプル・プログラム |
このソースコードでは、1点だけ面白い機能を利用しているので注意が必要である。11行目のWriteLineメソッドは何度も使ってきたが、実は複数の値を書式のなかに取り込んで出力する機能を持っている。第1引数の文字列中に{0}と書くと、第2引数値がそこに挿入され表示される。同様に{1}とすれば第3引数の値が、{2}とすれば第4引数の値が挿入される。例えば、「Console.WriteLine( "AB{0}EF", "CD" );」というコードは、「ABCDEF」を出力する。
さて、これを実行した結果は以下のようになる。
|
プログラムの実行結果 |
整数型変数のiの値と、これをi.ToString( )で文字列型に変換した変数sの値の双方とも、「123」となった。i.ToString( )が正しく機能していることが分かる。
|
数値としての値は123だが、これを文字列に変換した結果も、123となっている。間違いなく整数型変数に対して、ToString( )が機能していることが分かるだろう。
2つの名前を持つデータ型
intとSystem.Int32のような別名関係は、他のデータ型にもすべて存在する。名前の対応表を以下に示すとともに、それぞれのデータ型の簡単な説明も合わせて付ける。
予約語 |
別名 |
意味 |
sbyte |
System.SByte |
符号付き8bit整数 |
byte |
System.Byte |
符号なし8bit整数 |
short |
System.Int16 |
符号付き16bit整数 |
ushort |
System.UInt16 |
符号なし16bit整数 |
int |
System.Int32 |
符号付き32bit整数 |
uint |
System.UInt32 |
符号なし32bit整数 |
long |
System.Int64 |
符号付き64bit整数 |
ulong |
System.UInt64 |
符号なし64bit整数 |
char |
System.Char |
文字型 |
float |
System.Single |
単精度実数 |
double |
System.Double |
倍精度実数 |
bool |
System.Boolean |
論理型(falseとtrueのみ) |
decimal |
System.Decimal |
10進型 |
string |
System.String |
文字列型 |
さて、これらの別名が完全にイコールであることを示すために、最初のサンプル・ソースを別名で書いたものを示そう。
1: namespace ConsoleApplication6
2: {
3: using System;
4:
5: public class Class1
6: {
7: public static int Main(string[] args)
8: {
9: System.Int32 i=123;
10: System.String s = i.ToString();
11: Console.WriteLine( "i={0}, s={1}", i, s );
12: return 0;
13: }
14: }
15: } |
|
上のサンプル・プログラムを別名で記述し直したもの |
これは、intを「System.Int32」と、stringを「System.String」と書き直したものである。これを実行すると、まったく同じ結果になることが分かるだろう。
|
プログラムの実行結果 |
別名を用いてプログラムを書き直しても、実行結果はまったく同じである。
|
数値の範囲
C/C++プログラマに対する注意としては、それぞれのデータ型が扱う数値の範囲が言語仕様で決められているということである。JavaやVisual Basicでも、数値の範囲は言語仕様で決まっている。C#もそれと同じになる。
扱える数値の上限と下限は、それぞれのデータ型のMinValueメソッドとMaxValueメソッドで取得できる。これらは、staticなメソッドなので、System.Int16.MaxValueというような書式で指定する。これを用いて各データ型の上限と下限を出力するプログラムを書いてみよう。
1: namespace ConsoleApplication6
2: {
3: using System;
4:
5: public class Class1
6: {
7: public static int Main(string[] args)
8: {
9: Console.WriteLine( "System.SByte {0}, {1}",
10: System.SByte.MinValue, System.SByte.MaxValue );
11: Console.WriteLine( "System.Byte {0}, {1}",
12: System.Byte.MinValue, System.Byte.MaxValue );
13: Console.WriteLine( "System.Int16 {0}, {1}",
14: System.Int16.MinValue, System.Int16.MaxValue );
15: Console.WriteLine( "System.UInt16 {0}, {1}",
16: System.UInt16.MinValue, System.UInt16.MaxValue );
17: Console.WriteLine( "System.Int32 {0}, {1}",
18: System.Int32.MinValue, System.Int32.MaxValue );
19: Console.WriteLine( "System.UInt32 {0}, {1}",
20: System.UInt32.MinValue, System.UInt32.MaxValue );
21: Console.WriteLine( "System.Int64 {0}, {1}",
22: System.Int64.MinValue, System.Int64.MaxValue );
23: Console.WriteLine( "System.UInt64 {0}, {1}",
24: System.UInt64.MinValue, System.UInt64.MaxValue );
25: Console.WriteLine( "System.Char {0}, {1}",
26: (int)System.Char.MinValue, (int)System.Char.MaxValue);
27: Console.WriteLine( "System.Single {0}, {1}",
28: System.Single.MinValue, System.Single.MaxValue );
29: Console.WriteLine( "System.Double {0}, {1}",
30: System.Double.MinValue, System.Double.MaxValue );
31: Console.WriteLine( "System.Decimal {0}, {1}",
32: System.Decimal.MinValue, System.Decimal.MaxValue );
33: return 0;
34: }
35: }
36: } |
|
各データ型の上限値、下限値を表示するサンプル・プログラム |
このプログラムの実行結果は以下のようになる。
|
プログラムの実行結果 |
各データ型の下限値、上限値がそれぞれ表示されている。ここでSystem.Singleの上限である「3.4028234E38」は指数表示で、「3.4028234」掛ける10の38乗という意味になる。
|
整数関係のデータ型については特に説明の必要もないだろう。System.Charは文字型なので、そのままでは文字を出力してしまう。そのため、intへのキャストを入れて、数値として出力させている。プログラムの実行結果から、0〜65535が格納できることが分かるだろう。これはUnicodeの値である。System.SingleとSystem.Doubleは浮動小数点表記の実数型で、結果は指数表示になっている。「3.4028234E38」とは、「3.4028234」掛ける10の38乗という意味である。最後のSystem.Decimalは、高精度の計算ができる10進表記のデータ型である。この結果からは分からないが、小数も扱うことができる。特に、小数の計算を行うと、System.SingleやSystem.Doubleでは10進数と2進数の変換誤差などで結果が狂う場合もあるが、System.Decimalならずっと正確に計算できる。その代わり計算は遅くなる。スピードを取るか精度を取るかで選択されるべきものだろう。
初期化される変数値
変数を宣言して利用可能になった瞬間、Visual Basicなどでは、あらかじめ決まった値(例えばゼロ)が入っている。それに対して、Cなどでは不定(どんな値か分からない)になる。C#は、Cの流れを汲む言語であるが、この点に関しては別の立場を取っている。つまり、Visual Basicのように、変数を既定の値で初期化する。
変数を初期化しないと、万一、値を代入する前の変数を利用するコードがあると、実行するごとに挙動が変わる不安定なプログラムになる危険がある。また、バグを探そうにも、毎回挙動が変わるので、なかなか問題点を探しにくいという理由もある。変数を必ず初期化すると、これを回避できる。しかし、変数をいちいち初期化する処理を入れると、その分だけプログラムの実行速度が遅くなるという弊害がある。効率重視であれば、変数の初期化は行わない。安全重視なら初期化すべき、と言うことになる。そこで、C#は初期化するという選択を取ったわけである。
初期化される値は基本的にゼロである。浮動小数点型なら0.0になる。bool型はfalseである。
実際に初期化されている例を以下のプログラムで見てみよう。
1: namespace ConsoleApplication6
2: {
3: using System;
4:
5: public class Class1
6: {
7: private static int i;
8: public static int Main(string[] args)
9: {
10: Console.WriteLine( i );
11: return 0;
12: }
13: }
14: } |
|
変数の初期化を調査するサンプル・プログラム |
このプログラムでは、変数iに代入するコードは含まれていないが、何度実行しても、結果は必ず同じになる。実行した結果は以下のとおりである。
|
プログラムの実行結果 |
C#では、変数を宣言すると、何も代入しなくても既定の値で初期化される。例えばこの例では、int型変数を宣言し、明示的な初期化をしないで表示している。結果は、何度実行しても同じ「ゼロ」になる。 |
更新履歴 |
【6月1日】「数値の範囲」において、「これらは、staticなメソッドなので、System.Int16.MaxValueというような書式で指定する(ちなみに、int.MaxValueでは期待する結果が得られないようだ)。」となっていましたが、int.MaxValueも正しく動作することを確認しました。お詫びして訂正させていただきます。
|
|