C# 初級講座 |
![]() ![]() |
2023/10/14
この記事が対象とする製品・バージョン
![]() |
Visual Studio 2022 | ◎ | 対象です。 |
![]() |
Visual Studio 2019 | ◎ | 対象です。 |
![]() |
Visual Studio 2017 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2015 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2013 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2012 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2010 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2008 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio 2005 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio.NET 2003 | △ | 対象外ですが参考にはなります。 |
![]() |
Visual Studio.NET (2002) | △ | 対象外ですが参考にはなります。 |
Visual Studio Code | △ | 対象外ですが参考にはなります。 |
目次
C#などのプログラミング言語はそれ自体はほとんど何の機能もなく、フレームワークを制御することでさまざまな機能を実現します。
画像処理や音楽などのマルチメディア、WindowsなどのOSの制御、ファイル処理、印刷、ネットワークなどの様々な機能もそうですし、AIによる分析・予測や翻訳、巨大なデータの処理などクラウドの機能を利用するのもフレームワークを通して利用することになります。
C#で通常使う フレームワークはマイクロソフトの製の「.NET」という巨大なフレームワークです。この.NETを利用して、さらに便利な機能が構築され、それらがまた簡単に呼び出せるようにさまざま公開されています。呼び出せる機能をすべて「フレームワーク」とは分類できない場合もありますが、この記事では説明を簡単にするためにすべて「フレームワーク」に含むものとして扱います。
フレームワークの機能を C# から呼び出すには、クラスまたは構造体を使用します。
クラスまたは構造体はフレームワーク内に多数含まれており、数千個は存在していると思います。
クラスまたは構造体には、メソッド・プロパティ・コンストラクター・フィールド・イベント・演算子が0個以上含まれています。これらをメンバーと言います。C#のプログラムからこれらメンバーを呼び出すことでさまざまな機能を実現できます。
クラス(または構造体)のメンバーを自由に呼び出せるようになることが、クラス(または構造体)の機能を自由に使えることを意味します。
メンバーの種類で代表的なものはメソッドとプロパティです。
クラスのメンバーには静的メンバーと非静的メンバーの2種類があります。
つまり、メソッドには静的メソッドと非静的メソッドがあり、プロパティには静的プロパティと非静的プロパティがあり…という具合です。演算子にはこの区別はありません。今回は代表的なメンバーであるメソッドとプロパティを念頭に話を進めます。
静的メンバーと非静的メンバーとで呼び出し方が大きく異なります。
静的メンバーはプログラム中、クラス名を記述して直接呼び出すことができます。
非静的メンバーは「インスタンス」というものを対象にし、プログラム中でインスタンスを記述して呼び出す必要があります。
例として、Windows フォーム アプリ で使用する TextBoxクラス を使って説明します。
(Windowsフォームアプリケーションを体験していない方は 入門講座で体験できます。Clickイベントハンドラーの使用方法は理解している前提でこの後の説明を進めます。)
下記の設定で新規プロジェクトを作成してください。
プロジェクトテンプレート | Windows フォーム アプリ |
---|---|
プロジェクト名 | CallClassLesson |
ソリューション名 | CallClassLesson |
フレームワーク | .NET 6.0 |
Windows フォーム アプリではTextBoxをぺたぺたといくつでもフォームに貼り付けることができます。
1つのTextBoxというクラスからたくさんの分身を作り出すことができます。この分身が「インスタンス」というものです。
Windows フォーム アプリのフォームデザイナーでは既定ではインスタンスに「textBox1」、「textBox2」というような名前が付きます。「TextBox」がクラスの名前で、「textBox1」や「textBox2」はインスタンスの名前というわけです。
フォームに3つのTextBoxと1つのButtonを貼り付けて、次のようにしてみてください。
TextBoxはAppendTextというメソッド(読み方:AppendText = アペンドテキスト) を持っており、このメソッドを呼び出すことで、表示されている文字列を追加する処理を呼び出すことができます。
このメソッドは非静的メソッドです。
非静的メソッドなので、プログラム時には textBox1. や textBox2. というようにインスタンスを指定して呼び出す必要があります。実行しても対象のTextBoxだけに文字が追加されます。
たとえば、button1 の Clickイベントハンドラーに textBox2のAppendTextメソッドを呼び出す次のプログラムを記述してください。
private void button1_Click(object sender, EventArgs e)
{
textBox2.AppendText("Hello!");
}
これを実行すると、textBox2にだけ Hello! が追加されます。
同じTextBoxクラスなのに、textBox1とtextBox3という名前のインスタンスには何も起こらずtextBox2という名前のインスタンスだけが変化しています。
これがクラスとインスタンスの違いです。
一方、TextBoxには、MousePositionというプロパティ(読み方:MousePosition = マウスポジション)もあります。このプロパティはマウスの位置データを取得することができます。
このメソッドは静的メソッドです。
静的メソッドなので、プログラム時には TextBox というクラス名から呼び出すことができます。
button1のClickイベントハンドラーを次のように書き換えて試してみましょう。
private void button1_Click(object sender, EventArgs e)
{
Point pos = TextBox.MousePosition;
MessageBox.Show(pos.ToString());
}
見慣れないものもあるかもしれませんが、ここで注目してほしいのは MousePositionプロパティを呼び出すときに「TextBox」というクラス名を使っていることです。インスタンスの名前(textBox1, textBox2, textBox3)は登場していません。
なお、Visual Studioではクラスや構造体の名前は薄い青色で表示され、インスタンスの名前は黒い色で表示されます。
ここまでをまとめると、
・AppendTextメソッドとMousePositionプロパティはどちらも TextBoxクラスのメンバーです。
・非静的メンバーである AppendTextメソッドは textBox2.AppendText のようにインスタンスを記述して呼び出しました。「textBox2」がインスタンス名です。
・静的メンバーである MousePositionプロパティは TextBox.MousePosition のようにクラス名を記述して呼び出しました。「TextBox」がクラス名です。
静的メンバーと非静的メンバーの区別はリファレンスにも記載してありますが、言葉の意味を考えればわかります。
「静的」とはものごとが静止している様子を意味します。
マウスの位置はどのTextBoxから取得しても同じ情報なので、インスタンスがどんなに動こうが変化しようが関係ない情報です。つまり「静的に」表現される情報です。だからこれは静的プロパティです。
AppendTextメソッドは逆にそれぞれのインスタンスの状態や状況によってどう変化するかが変わるので「静的」とは呼べません。ですから非静的メソッドです。
クラスのインスタンスを作成するにはコンストラクターというものを利用します。
Windows フォーム アプリのフォームデザイナーではマウスでぺたぺたとTextBoxやButtonを貼り付けると自動的にコンストラクターを呼び出してインスタンスを作成してくれて、プロパティも設定してくれて大変便利ですが、この便利な機能を利用できるのはTextBoxやButtonなどWindows フォーム アプリ用のコントロールとして設計されたクラスだけです。
この他の大部分のクラスは、自分のプログラムでインスタンスを作成することが必要になります。必要であればTextBoxやButtonのインスタンスを自分のプログラムで作成することもできます。
クラスのインスタンスを作成することを「インスタンス化」・「インスタンシング」と呼ぶ場合もあります。
メソッドやプロパティと違ってコンストラクターには名前がついていませんので名前で呼び出すことはできません。C#の new キーワード + クラス名 の構文を使ってコンストラクターを呼び出すことができます。
通常は作成したインスタンスを変数に代入して、後でメソッドやプロパティを呼び出すことができるようにしておきます。
たとえば、ランダムな値を生成するRandomクラス(読み方:Random = ランダム)クラスのインスタンスを作成して変数 r に代入するには次のようにします。
Random r = new Random();
左側の Random は クラスの名前であり型の名前です。クラスのインスタンスを作成するとき、クラスはそのインスタンスを表す変数の型でもあります。つまり、変数 r は Random型です。
右辺のRandomはコンストラクターの呼び出しです。呼び出しを表すために必ず ( ) を付ける必要があります。
このプログラムだと「Random」が2回出現して少しくどいようにも思えます。キーワード var (読み方:var=バー)を使って、少しだけ簡潔に書くこともできます。
var r = new Random();
この2つのプログラムは全く同じ意味です。new Random() という呼び出しで生成されるインスタンスは Random型であることはわかっているので、プログラマー自身が記述しなくてもvarキーワードを使うことでC#が型を推論してくれます。これは「型推論」という機能で、コンストラクター呼び出し以外でも変数を宣言するときに値を代入している場合は、varを使うことで型を明記しないで済ませることができます。
型推論は使用できない個所もあります。(クラス直下では使用できません)。
さらに、ちょっと混乱されるかもしれませんが、次のように省略して書く特別な構文もあります。
Random r = new();
これは、Random型の変数のインスタンスを作成しようとしているのだから、Randomクラスのコンストラクターを呼び出しているに決まっているので、記述を省略できるという発想から生まれた構文です。varを使った型推論と同じような発想ですね。
ちょっと説明がややこしくなって今いましたが、多くのプログラマーは var を使って型推論させる書き方を好んでいるように感じます。
インスタンスが作れれば非静的メンバーを呼び出せます。Randomクラスにはランダムな整数を生成するNextメソッド(読み方:Next = ネクスト)がありますので、呼び出してみましょう。
var r = new Random();
int number1 = r.Next(1, 101);
int number2 = r.Next(1, 101);
int number3 = r.Next(1, 101);
MessageBox.Show($"{number1} {number2} {number3}");
クラスによってはコンストラクターでインスタンスを作成するときに追加情報が必要なものがあります。
たとえばフォルダーを表すDirectoryInfoクラス(読み方:DirectoryInfo = ディレクトリーインフォ)は、インスタンスを作成するときに「対象はどのフォルダー?」という情報を追加で指定する必要があります。
//コンストラクターを呼び出すときにフォルダーのパスを指定します。
var folder = new DirectoryInfo(@"C:\test");
//インスタンスの最終更新日を表すLastWriteTimeプロパティを呼び出します。
DateTime updateTime = folder.LastWriteTime;
MessageBox.Show(updateTime.ToString());
このようにコンストラクターに渡される追加情報のことを「引数」(ひきすう)と呼びます。これはメソッドを呼び出すときに引数が必要な場合があるのと同じことです。さきほどもTextBox.AppendTextメソッドの呼び出しやRandom.Nextメソッドの呼び出し時に引数を指定する例を紹介しました。
メソッドの引数と同様にコンストラクターの呼び出しに2つ以上の引数が必要な場合もありますし、同じコンストラクターの呼び出しでも引数の指定の仕方が何パターンがある場合があります。このようなパターンを「オーバーロード」と呼びます。
参考に、引数を2つ要求するコンストラクターの例を紹介しておきます。
ファイルへの書き込みを行うStreamWriterクラス(読み方:StreamWriter = ストリームライター)は、第1引数として対象のファイルのパス、第2引数として追加書きするかどうかを指定します。第2引数にtrueを指定した場合、既に対象のファイルが存在する場合後ろに文字列を追加します。falseの場合、既にファイルが存在すれば上書きします。
//第1引数は書き込み対象のファイル、第2引数はtrueなら追加書き、Falseなら上書き。
var writer = new StreamWriter(@"C:\test\sample.txt", false);
writer.Write("Hello!");
//StreamWriterは使用終了後必ず Dispose メソッドを呼び出すようにします。
writer.Dispose();
インスタンスを変数に代入することは多くの場合お勧めではありますが、必須ではありません。
次の例は PerformanceCounterクラス (読み方:PerformanceCounter = パフォーマンスカウンター)クラスを使って実行時点で使用可能なメモリ量をメガバイト単位で取得する例です。
この例は、PerformaceCounterクラスのインスタンスを変数 counterに代入し、変数を経由して非静的メソッドの NextValue を呼び出しています。
var counter = new System.Diagnostics.PerformanceCounter("Memory", "Available MBytes");
float freeMemory = counter.NextValue();
MessageBox.Show($"現在の使用可能メモリ:{freeMemory:#,0} MB");
PerformanceCounterクラスの属する System.Diagnostics 名前空間 (読み方:Diagnositcs=ダイアグノスティクス)は既定で省略可能な名前空間ではないので、この例では名前空間も明記しています。
また、MessageBox.Show の引数内にある {freeMemory:#,0} は変数 freeMemory の値を3桁区切りのカンマを付けた文字列にするという意味です。このような値の表示形式のことを「書式」と呼びます。書式の指定には #,0 のような独特な表現を使用します。書式指定を省略して単に {freeMemory} と記述することもできます。
これを変数counter を経由しないで直接インスタンスからNextValueメソッドを呼び出すには次のようにします。
float freeMemory = (new System.Diagnostics.PerformanceCounter("Memory", "Available MBytes")).NextValue();
MessageBox.Show($"現在の使用可能メモリ:{freeMemory:#,0} MB");
変数への代入を省略したので、プログラム行数は1行減りましたが、あまりわかりやすくはありませんね。( ) が増えている点にも注意してください。特に理由がなければ変数に代入したほうがわかりやすいので代入することをお勧めします。
この例ではどちらの場合も new を1回使用しているため、コンストラクターが1回呼び出されます。変数の仕様有無の違いはありますが機能・性能は同じです。
インスタンスの作成は、プログラムの処理の中では比較的重い処理なので不必要に大量のインスタンスを作成することは推奨されません。newの数が不必要に多くならないように気をつけてください。例外的にnew以外の手段でインスタンスが作成される場合もあるため new だけ気にしていれば良いというわけではありませんが通常は十分です。
無駄なnewが1個や2個実行されるというレベルは性能上の問題はまずありません。100個・200個というレベルで無駄なnewの実行がある場合はプログラムを変えるべきです。
whileなどの繰り返し実行する構文を利用すると、信じられないことに無駄なnewを何万回も実行してしまう場合があります。(本当にあります。私はシステム開発の現場で何度か目撃しています。)
次の回では、実際にいろいろなメソッドを呼び出してみます。