連載
» 2002年11月06日 00時00分 UPDATE

連載 改訂版 C#入門:第12章 インデクサとプロパティ (1/4)

オブジェクトを配列のようにアクセス可能にする「インデクサ」と、get/setアクセサをシンプルに記述できる「プロパティ」は、C#の洗練された機能だ。

[川俣晶(http://www.autumn.org/),(株)ピーデー(http://www.piedey.co.jp/)]
連載 改訂版 C#入門
Insider.NET

 

「連載 改訂版 C#入門」のインデックス

連載目次

 本記事は、(株)技術評論社が発行する書籍『新プログラミング環境 C#がわかる+使える』から許可を得て転載したものです。同書籍に関する詳しい情報については、本記事の最後に掲載しています。

 C#には、CやC++にはない「インデクサ」や「プロパティ」という機能がある。これらは、あらかじめ定義した処理を呼び出す方法であり、役割はメソッドに近いといえる。しかし、書式としては、メンバ変数や配列のように見えるものを記述可能である点が異なっている。本章では、インデクサとプロパティを解説する。

12-1 インデクサとは何か?

 まず、List 12-1のサンプル・ソースを見ていただきたい。文字列を1文字ずつ表示するという機能を持ったプログラムである。

  1: using System;
  2:
  3: namespace Sample001
  4: {
  5:   class Class1
  6:   {
  7:     [STAThread]
  8:     static void Main(string[] args)
  9:     {
 10:       string s = "Hello!";
 11:       for( int i=0; i<s.Length; i++ )
 12:       {
 13:         Console.WriteLine( s[i] );
 14:       }
 15:     }
 16:   }
 17: }

List 12-1

 このプログラムを実行するとFig.12-1のようになる。

dt-fig_12_01.gif Fig.12-1

 さて、このサンプル・ソースで注目すべき点は、13行目の「s[i]」という記述である。

 特に注意が必要なのがC/C++/Javaプログラマーである。それ以外の方は、この先の「C/C++/Javaプログラマーへの注意はここまでである。」という箇所の前まで読み飛ばしてかまわない。C/C++/Javaの構文で考えれば、「s[i]」は配列の値を参照しているように見える。もちろん、C#でも、この構文は通常配列へのアクセスに使われる。しかし、「[]」でくくる構文は、配列へのアクセスにしか使われないものではない。実は、このサンプル・ソースでは、配列ではなくインデクサと呼ばれる機能へのアクセスに使われている。これは、C++で演算子[]をオーバーライドする場合と類似の機能なので、演算子のオーバーライドを理解しているC++プログラマーは容易に理解できるかもしれない。演算子のオーバーライドの機能を持たないC/Javaに慣れているプログラマーは要注意である。配列とインデクサはまったく違う機能なので、両者を区別することはC#を理解するうえで重要なポイントになる。

 余談だが、配列にアクセスするC++(中身はほとんどC)のサンプル・ソースをList 12-2に示す。

  1: #include "stdio.h"
  2: #include "string.h"
  3:
  4: int main(int argc, char* argv[])
  5: {
  6:   char s[] = "Hello!";
  7:   for( int i=0; i<strlen(s); i++ )
  8:   {
  9:     printf( "%c\n", s[i] );
 10:   }
 11:   return 0;
 12: }

List 12-2

 このプログラムを実行するとFig.12-2のようになる。

dt-fig_12_02.gif Fig.12-2

 このサンプル・ソースの9行目に記述されている「s[i]」は、配列へのアクセスである。C/C++では、文字列は文字の配列として表現されているので、文字列は、通常、配列そのものである。C#では文字列は文字列型のオブジェクトであり、配列とは違うものなので、最初のサンプルコードの「s[i]」とは機能的に異なっているのである。見かけは同じに見えるので注意が必要である。

 C/C++/Javaプログラマーへの注意はここまでである。読み飛ばした人はここから続きを読んでいただきたい。

 そもそも、インデクサとは一体何だろうか? インデクサが提供する機能とは、「あたかも配列変数にアクセスするかのようなソース・コードを記述することで、ユーザーがあらかじめ記述したコードを実行させる機能」といえる。上記の例である「s[i]」の場合、パッと見ると、sという配列変数のi番目の要素を取り出しているように見える。しかし、sは、string(System.Stringクラスの別名)型であるので、配列ではない。インデクサの機能が、文字列型のオブジェクトを配列であるかのように見せかけているのである。そして、インデクサにアクセスすると、配列にアクセスする代わりに、リファレンス・マニュアルに記載されているString.Charsプロパティの機能が呼び出されるのである(プロパティについては本章後半で解説する)。リファレンス・マニュアルでString.Charsプロパティを調べていただければ分かると思うが、このプロパティはCharsという名前だが、C#ではインデクサとして実現されていることが説明されている。つまり、ほかのプログラミング言語から利用する場合、この機能は単なるプロパティにすぎないわけであり、配列とはまったく無縁の機能なのである。

 このように、.NET Frameworkのクラス・ライブラリ・リファレンスの中には、名前が付いているにもかかわらず、C#ではインデクサとして実装されているものが多く見られる。そのため、インデクサを知らずにC#プログラミングはできないと思ってよいだろう。

12-2 インデクサと配列の違い

 インデクサと配列の違いを、もっと具体的に調べてみよう。List 12-3のサンプル・ソース・コードでは、ほぼ同じ情報をインデクサと配列で表現してみた。なお、配列の詳細は、後の章で詳しく説明する。いまは、だいたいこんなものかと思って見ていただきたい。

  1: using System;
  2:
  3: namespace Sample002
  4: {
  5:   class Class1
  6:   {
  7:     [STAThread]
  8:     static void Main(string[] args)
  9:     {
 10:       string s = "Hello!";
 11:       char [] a = { 'H', 'e', 'l', 'l', 'o', '!' };
 12:       Console.WriteLine( a.GetUpperBound(0) );
 13:       // Console.WriteLine( s.GetUpperBound(0) );  // 'string' に 'GetUpperBound' の定義がありません。
 14:       Console.WriteLine( s.ToUpper() );
 15:       // Console.WriteLine( a.ToUpper() ); // 'System.Array' に 'ToUpper' の定義がありません。
 16:       Console.WriteLine( s.GetType().FullName );
 17:       Console.WriteLine( a.GetType().FullName );
 18:     }
 19:   }
 20: }

List 12-3

 このプログラムを実行するとFig.12-3のようになる。

dt-fig_12_03.gif Fig.12-3

 List 12-3でまず注意していただきたいのが、10〜11行目である。10行目では、文字列、11行目では文字の配列が宣言されている。C/C++では基本的に文字列と文字の配列はイコールであったが、C#ではまったく別個の方法で宣言されていることが分かるだろう。次に注目していただきたいのは、12〜15行目である。コメントアウトされている行は、コードにしてしまうとエラーになる行である。12〜13行目では、GetUpperBoundというメソッドを呼んでいるが、これは、配列の上限の添え字の値を返すものである。配列aには適用できるが文字列sには適用できない。文字列を扱うSystem.stringクラスにインデクサは存在するが、GetUpperBoundメソッドは存在しないのである。同じように、14〜15行目では、文字列を大文字に直すToUpperメソッドがあるが、配列の機能を定義するSystem.ArrayクラスにToUpperメソッドは存在しないことを示している。

 16〜17行目のコードで、実際にそれぞれの厳密な型の名前を表示させているが、sはSystem.Stringで、aはSystem.Char[](char型の配列のフルネーム)となっており、まったく別個のデータ型(クラス)として扱われていることが分かると思う。つまり、インデクサによって配列のようにアクセスできるクラスがあるからといって、そのクラスが配列の持つ全機能を使えるわけではないのである。

       1|2|3|4 次のページへ

Copyright© 1999-2014 Digital Advantage Corp. All Rights Reserved.

TechTargetジャパン

メルマガ購読キャンペーン

コメント

ツイート

ホワイトペーパー(TechTargetジャパン)

注目のテーマ

転職/派遣情報を探す

【転職サーチ】SIer/Web企業/新規事業 スマホ開発で、あなたのキャリアを生かす

「派遣・フリーで働くメリット」とは? 活躍する派遣エンジニアの本音

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。