連載
» 2015年09月15日 05時00分 公開

連載:簡単! Visual Studio 2015入門:第4回 Visual Studio 2015のひな型コードを理解する (3/4)

[かわさきしんじ,Insider.NET編集部]

Windowsフォームデザイナーで生成されたコード(Form1.Designer.csファイル)

 次のコードはForm1.Designer.csファイルの内容である。

namespace WindowsFormsApplication1
{
  partial class Form1
  {
    /// <summary>
    /// 必要なデザイナー変数です。
    /// </summary>
    private System.ComponentModel.IContainer components = null

    /// <summary>
    /// 使用中のリソースを全てクリーンアップします。
    /// </summary>
    /// <param name="disposing">マネージ リソースを破棄する場合は true を指定し、その他の場合は false を指定します。</param>
    protected override void Dispose(bool disposing)
    {
      ……中略……
    }

    #region Windows フォーム デザイナーで生成されたコード
    /// <summary>
    /// デザイナー サポートに必要なメソッドです。このメソッドの内容を
    /// コード エディターで変更しないでください。
    /// </summary>
    private void InitializeComponent()
    {
      ……中略……
    }
    #endregion
    ……中略……
  }
}

Windowsアプリのフォームデザイナー用のコード(Form1.Designer.csファイル)
Form1.Designer.csファイルとForm1.csファイルの二つのファイルに部分クラスとして定義されたForm1クラスには、一つのフィールド変数と三つのメソッドがある(components変数、Form1コンストラクターメソッド、Disposeメソッド、InitializeComponentメソッド)。なお、InitializeComponentメソッドの前後にある「#region Windows <コメント>」〜「#endregion」の部分は「アウトライン機能」と呼ばれ、コードを折りたたんで非表示にすることが可能な場所である。詳しくは、「.NET TIPS:VS.NETでソース・コードを見やすくするには?」を参照していただきたい。

 Form1.Designer.csファイルに部分クラスとして分離されたForm1クラスには、次のような変数(「フィールド変数」とも呼ばれる)とメソッドがある。

  1. フィールド変数: private System.ComponentModel.IContainer components
  2. メソッド: protected override void Dispose(bool disposing)
  3. メソッド: private void InitializeComponent()

 このように、先ほどのForm1.csファイルのForm1クラスのコンストラクターで呼び出されていたInitializeComponentメソッドは、Form1.Designer.csファイルに部分クラスとして分離されているForm1クラス内にあることが分かった。なお、Form1クラスを正確に宣言すると「public partial class Form1 : System.Windows.Forms.Form」と記述しなければならないわけだが、上記コードを見れば分かるように、部分クラスではアクセス修飾子(この例では「public」)や基底クラス(この例では「: System.Windows.Forms.Form」)は省略可能だ*3

*3 部分クラスとして分離されたクラスのどれか一つにアクセス修飾子と基底クラスの宣言が含まれていれば、その他のクラスではこれらを省略できる。本稿で説明するWindowsアプリのひな型コードの例では、Form1.csファイルのForm1クラスの方にアクセス修飾子と基底クラスが宣言されているので、Form1.Designer.csファイルのForm1クラスでは省略可能となる。


 それでは、これらのフィールド変数やメソッドについて、個別に解説していこう。

1. components変数

 1の「components」変数はクラス内で使用されるフィールド変数で、コンポーネントを管理するためのものだ(「コンテナー」と呼ばれる)。コンポーネントについては、改訂版 C#入門の「Column − コンポーネントとコントロール -」を参照してほしい。

private System.ComponentModel.IContainer components = null;

components変数の宣言

 ここではcomponents変数に「null」が代入されているが、(Windowsフォームデザイナー上に[ツールボックス]から例えばTimerなどのコンポーネントを追加した場合には*43で説明するInitializeComponentメソッドの中に次のようなコードが自動的に生成されるため、ほぼ初期状態のContainerオブジェクト(System.ComponentModel名前空間)がcomponents変数に格納されることになる(そして、その後、追加したTimerコンポーネントがそのContainerオブジェクトに格納される)。

this.components = new System.ComponentModel.Container();

WindowsフォームデザイナーによりForm1.Designer.csファイルに自動生成されるコードの例(components変数へのContainerオブジェクトの代入)

 このcomponents変数は、次に説明する「2. Disposeメソッドで終了処理」で使用される。

*4 ここでいう「コンポーネント」とは、Buttonコントロールなどの目に見えるUI要素を持ったプログラム部品ではなく、Timerコンポーネントなどの目には見えないがWindowsフォームに配置して何らかの処理に使用するプログラム部品のことだ。Windowsフォームアプリでは、components変数を使ってコンポーネントの管理を行っている。ただし、初めのうちはあまり気にしなくてもよいだろう。


2. Disposeメソッドで終了処理

 2の「protected override void Dispose(bool disposing)」では、終了処理(=後処理。不要なデータを破棄する処理や、クラス終了時に実行しなければならない処理)を記述する(上の例では、追加したTimerコンポーネントの破棄などが行われる)。ここでは、初期化処理はコンストラクター、終了処理はDisposeメソッドで行うと、対にして覚えておけばよい(終了処理については下のコラムを参照)。

[コラム] ファイナライザー(=デストラクター)について

 コンストラクターの正反対の処理を行うためのメソッドは、ファイナライザーである(「デストラクター」とも呼ばれる)。しかし.NETでは、ガベージコレクション機能(=メモリを自動的に管理するための.NETの機能で、これによって.NETではメモリリークが発生しにくくなっている)があるため、ファイナライザーを呼び出すタイミングが不確定になっている。そこで、終了処理を明示的に行えるものとしてDisposeメソッドが用意されている。このDisposeメソッドを明示的に呼び出せば、確実にその場で終了処理が実行できる。

 なお、暗黙的に終了処理を行うためには(つまり、ガベージコレクション機能に自動的に後処理を行わせるには)、Disposeメソッドではなくファイナライザーを実装することになる。ファイナライザーを実装するには、コンストラクター名の先頭にチルダ(~)を挿入したメソッド名で「~Form1()」と記述するだけだ(VBでは「Protected Overrides Sub Finalize()」というメソッド名になる)。終了処理についてさらに詳しくは「.NET TIPS:確実な終了処理を行うには?」を参照するとよい。


 Disposeメソッドでは、protected修飾子の次に、さらにoverride修飾子がある。C#のoverride修飾子(VBではOverrides修飾子)は、継承されたクラスでのみ使用できる修飾子で、基底クラスにあるメソッドを新しい派生クラスのメソッドで置き換えることを示すためのものだ。

 つまり、このひな型コードでは、「基底クラスであるFormクラス(System.Windows.Forms名前空間)のDisposeメソッドを、派生クラスであるForm1クラス(WindowsFormsApplication1名前空間)のDisposeメソッドで置き換える」ということを示している。このようなメソッドの置き換えを、オブジェクト指向言語では、メソッドの「オーバーライド」と呼ぶ。

 Disposeメソッドの実装内容は次のようになっている。

protected override void Dispose(bool disposing)
{
  if (disposing && (components != null)) 
  {
    components.Dispose();
  }
  base.Dispose(disposing);
}

Disposeメソッドの実装

 まず「if (<bool値>)」というコードはそのまま英語の意味で、「もしbool値(=trueとfalseという2種類の値のみを入れられる)がtrueなら、続く { …… } のスコープのコードを実行する」という意味である。「&&」演算子は論理積を表し、日本語で表現するなら「かつ」という語句に当てはまる。すなわち「A && B」は「AかつB」という意味になる。まとめると、上記コードの「if (disposing && (components != null))」は、「もしdisposingパラメーターの値がtrueで、かつ、(components != null)がtrueなら、続く { …… } のスコープのコードを実行する」という意味になる。

 そして「disposing」はDisposeメソッドのパラメーターに指定されたbool型の変数(=bool値)であり、Form1クラスのDisposeメソッドについては通常、この値はtrueとなる*5。次に「(components != null)」というコードだが、C#の「!=」比較演算子は「同じではない」を表すので(ちなみに「==」比較演算子が「同じである」を表す)、このコードの意味は「components変数がnullと同じではない」となる。前述の通り、WindowsフォームにTimerなどのコンポーネントを追加したとしたら、components変数には3のInitializeComponentメソッドでContainerオブジェクトが代入されるので、「components変数がnullと同じではない」は「正しい(=true)」という結果になる。従って、「disposing」パラメーターの値がtrue、かつ、「(components != null)」がtrueなので、「if (disposing && (components != null))」の次にある { …… } のスコープのコードが実行されることになる。

*5 このDisposeメソッドのdisposingパラメーターは、Disposeメソッドがユーザーのコードによって直接もしくは間接的に呼び出されたときにtrueとなり、共通言語ランタイム(=.NET実行エンジン)のファイナライザーによって呼び出されたときにはfalseとなる。本稿で説明しているForm1クラスのように、Application.Runメソッドから実行されたクラスのDisposeメソッドの場合には、Runメソッドの内部コードから間接的にDisposeメソッドが呼ばれるため、disposingパラメーターの値はtrueとなり、components変数がnullでなければ(Windowsフォームにコンポーネントを追加していれば) { …… } のスコープのコードが実行されることになる。


 そのスコープ内には「components.Dispose();」というコードがあるが、これはcomponents変数の終了処理を行うために、さらにcomponents変数のDisposeメソッドを呼び出すコードである*6

*6 Windowsフォームデザイナーでコンポーネントを追加すると、コンテナーであるcomponents変数にそのコンポーネントが登録される。そこで登録された全てのコンポーネントのDisposeメソッドが、このcomponents変数のDisposeメソッドの中から呼び出されるため、全てのコンポーネントのリソース破棄などの後処理を漏れなく実行できるという仕組みになっている。


 最後にある「base.Dispose(disposing);」は、基底クラスのDisposeメソッドを呼び出すコードである。前回の継承の説明でも述べたようにForm1クラスには、継承元となる基底クラスが存在する。その基底クラスのオブジェクトは「base」というキーワードにより参照できる(VBでは、「MyBase」というキーワード)。このキーワードは通常のオブジェクトのように「オブジェクト名.メソッド名」の形式で利用できる。よって、この「base.Dispose(disposing);」というコードは、「基底クラスにあるDisposeメソッドを呼び出す」という処理コードになる。

3. InitializeComponentメソッドで“実際の”初期化処理

 3の「private void InitializeComponent()」は、Form1.csファイルに記述されたForm1クラスのコンストラクターから呼び出されるクラス内部専用(=private修飾子)のメソッドである。InitializeComponentメソッドの内容を見ると、次のようになっている(一部省略。下記のようにcomponents変数が設定されるのは、Windowsフォームにコンポーネントが追加されているなど、特定の場合のみ)。

private void InitializeComponent()
{
  this.components = new System.ComponentModel.Container();
  this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  this.Text = "Form1";
}

InitializeComponentメソッドの実装

 メソッドの中の最初の行は、前述の「1. components変数」で説明した。

 2行目の「this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;」は、Windowsフォームやその中のコントロールのサイズを自動調整(=自動スケーリング)する際の基準を示すモードを指定する。代表的なモードには以下のものがある。この表を見ると、ここではフォントサイズを基準にした自動スケーリングを行うモードを指定していることが分かる。

モードの種類 自動スケーリングの基準
System.Windows.Forms.AutoScaleMode.Dpi ディスプレイ解像度
System.Windows.Forms.AutoScaleMode.Font フォントサイズ
自動スケーリングの基準を示すモード

 3行目の「this.Text = "Form1";」は、Windowsフォームのタイトルテキストを指定するためのコードで、ここでは「Form1」を指定している。この値を変更するには、前々回に説明したWindowsフォームデザイナー画面で、[プロパティ]ウィンドウの[Text]プロパティを書き換えればよい。

 以上のようにInitializeComponentメソッド内では、Form1オブジェクト(=Windowsフォーム画面)の初期値を設定している。

 フォームにボタンなどを配置することで、上記のコードがどのように変化するかを読み解いていくと理解が進むかもしれないので、興味のある方はぜひ試してみてほしい。では、最後にここまでの説明を踏まえてひな型コード全体の実行の流れを見てみよう。

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

@ITのメールマガジン(無料)

✔ 【@IT通信】
  編集部のおすすめ記事、限定コラムをお届け
✔ 【@IT新着速報】
  新着記事・速報をまとめてお届け
✔ 【@IT自分戦略研究所Weekly】
  転職支援情報やキャリアアップ情報をお届け

RSSについて

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

メールマガジン登録

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