連載

C#入門

第5 C#のデータ型

(株)ピーデー
川俣 晶
2001/05/26


ボクシング(boxing)

 複数のデータを一括して扱う処理を記述する場合に、どのようなデータでも収納できる便利な機能を記述できるとプログラムがすっきりする。だが、実用言語で、これを達成したものは多くはない。例えばJavaでは、数値型はクラスではないため、任意のクラスのインスタンスを扱う入れ物となるクラスを設計しても、そのままでは数値を格納できない。そのため、数値を格納するラッパ・クラス(wrapper class)のインスタンスに一度数値を入れてから、それを格納する必要がある。Visual Basic 6.0のVariant型は何でも格納できるのだが、その代わり、値を入れるときは普通の代入、参照を代入する場合はsetステートメントと使い分ける必要がある。

 これに対して、C#は、すべてのクラスのスーパー・クラスを辿っていくと、最後にたどり着くobject型に、すべてのデータの参照を格納することができる。ちなみに、objectはSystem.Objectの別名である。実際に、整数、実数、文字列、Structs、クラスの5種類の情報を1個のobject型の配列に代入できる例を示そう。

  1: namespace ConsoleApplication8
  2: {
  3:   using System;
  4:
  5:   public struct Structs1
  6:   {
  7:     // 中身はない
  8:   }
  9:
 10:   public class Class1
 11:   {
 12:     public static int Main(string[] args)
 13:     {
 14:       object [] test = new object[5];
 15:       test[0] = (int)1;
 16:       test[1] = (float)0.1;
 17:       test[2] = (string)"Hello!";
 18:       test[3] = new Structs1();
 19:       test[4] = new Class1();
 20:       for( int i=0; i<5; i++ )
 21:       {
 22:         Console.WriteLine( "Class={0}, Value={1}",
 23:           test[i].GetType().FullName, test[i].ToString() );
 24:       }
 25:       return 0;
 26:     }
 27:   }
 28: }
1つのオブジェクトにさまざまな型の値を代入するサンプル・プログラム
これまでの常識では、「object」はクラスであり、クラスは参照型なのだから、整数値などは代入できないはずだ。しかし実際には、このプログラムは問題なくコンパイル・実行することができる。
5:
18行目で代入に使用する値型のStructs。ただし今回はテストなので、内部には何も宣言していない。
14:
object型の5つの要素からなる配列を作成し、変数「test」に代入する。
15:
整数型の値「1」を配列testの0番目の要素として代入する。
16:
浮動小数点値の「0.1」を配列testの1番目の要素として代入する。
17:
「Hello!」という文字列を配列testの2番目の要素として代入する。
18:
Structsとして宣言されたStructs1のインスタンスを作成し、それを配列testの3番目の要素として代入する。
19:
Class1(自分自身)のインスタンスを作成し、それを配列testの4番目の要素として代入する。
20〜24:
配列testの各要素について、データ型と値を表示する。GetType( )はデータ型に関する情報を取得するためのメソッドで、「GetType( ).FullName」によって、そのデータ型のネームスペースを含むフルネームが得られる。

 見慣れない記述もあると思うので解説する。23行目のGetType( )はデータ型に関する情報を得るためのメソッドである。どのオブジェクトに対しても使用できる。そして、FullNameは、そのデータ型のnamespaceを含むフルネームを得るためのプロパティである。もう1点、補足するなら、クラスやStructsに対して、ToString( )をオーバーライドせずに呼び出すと、そのクラスやStructsの名前を返す機能が備わっている。

 このコードは、これまでの解説から考えればあり得ないコードである。なぜなら、objectはクラスであり、クラスは参照型であって、値型とは違うからだ。値型の整数が簡単に代入できるわけがない。つまり、値型である整数、実数、文字列、Structsはobject型に代入できないのが筋なのである。

 にもかかわらず、これはコンパイルでき実行できる。実行結果を以下に示す。

サンプル・プログラムの実行結果
このサンプルでは、同じobjectクラスを使って、さまざまな型の値を保持している。これを可能にしているのは、C#の「ボクシング(boxing)」と呼ばれる機能である。

 種明かしをしよう。これは、ボクシング(boxing)という機能によって実現されている。C#では、値型の値をobjectなどの参照型に代入しようとすると、ボクシングという機能が自動的に挿入される。ボクシングは、値型を包み込むクラスを自動的に生成する。クラスは参照型なので、そのまま参照型として利用できる。この機能により、object型の変数には、C#のあらゆる型のデータへの参照が代入できるのである。これにより、どんなデータ型でも収納できる便利なクラスが非常に作りやすくなっている。また、ソースコードもすっきりと見通しがよくなる。

 ただし、ボクシングは万能ではないことに注意が必要である。ボクシングとは要するに、暗黙のうちにクッションとなるオブジェクトを自動的に生成して、そのなかに値型の値をコピーすることを意味する。つまり、元々の値型の値を参照するわけではないのである。また、あくまでボクシングはデータをコピーする行為であるため、元のデータを変更しても、それが反映されるわけではない。

 このようにボクシングは便利ではあるが、込み入った使い方をしようとすると、トラブルの元になる場合もある。値型と参照型の違いは、きちんと意識して利用するようにしよう。

まとめ

 Structsとボクシングの存在は、C#とJavaを大きく隔てる特徴と言える。また、この2つはC++にもない機能であり、既存のプログラム言語の利用者は戸惑うかもしれない。この2つは、正しい理解抜きで使うと、かえってトラブルを起こしかねない危険もある。しかし、分かりやすいソースを書くということと、有限の資源を効率よく使うプログラミングを両立させるという意味では、なくてはならない機能と言える。とはいえ、どんな機能にせよ、それを使うのは人間である。主旨を誤解して、おかしなプログラムにしてしまうのも人間なら、使いこなして効率アップを達成するのも人間である。便利な機能を使いこなすには、それらを正しく理解することが欠かせない。

 次回は、データの扱いをもっと深めていこうと考えている。詳しい変数の説明などを行う予定である。

 それでは次回もLet's See Sharp!End of Article


 INDEX
  C#入門 第5回 C#のデータ型
    1.整数型からメソッドを呼ぶ
    2.値型と参照型
  3. ボクシング(boxing)
 
「C#入門」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間