VB6開発者向け:C#で始める.NETプログラミング

第8回 オブジェクト指向プログラミングの省力化

この記事を読むのに必要な時間:およそ 8.5 分

クラスの継承について
public partial class Logic : Component, INotifyPropertyChanged

基本クラスがComponentになっています。 C#では継承できるクラスは1つだけになるので,前回のようにNotifyPropertyChangedクラスを自作して実装を書いたものを利用することはできません。 ただし,インターフェイスは複数継承できます。

そこで,INotifyPropertyChangedインターフェイスを継承してNotifyPropertyChangedクラスの実装をLogicクラスに持たせています。

コンストラクタ

今回のコンストラクタは,引数のないコンストラクタと,IContainer型引数を受け取るコンストラクタの2つ存在します。 これらのコンストラクタは自動生成されたものです。

public Logic() {
    InitializeComponent();
}

public Logic(IContainer container) {
    container.Add(this);
    InitializeComponent();
}

C#では,コンストラクタに限らず,引数の型や数が異なる場合に同じメソッド名を複数持つことができます。 これをOverloadと呼びます。

BindingSourceプロパティ

VB6では,フォームオブジェクトに配置されたコントロールへ外部からアクセスすることができました。 しかしC#では,カプセル化という意味から,必要に応じて公開するという意味で非公開になっています。

public System.Windows.Forms.BindingSource BindingSource {
    get { return this.bindingSource1; }
}

BindingSourceはフォーム上のユーザーコントロールとバインドさせる必要があるため,このコントロールのオブジェクトをプロパティとして公開します。

DataSetのデータを充填する

フォームが開いたタイミングで,DataSetにデータを充填できるようにFillメソッドを作成して公開します。

public void Fill() {
    this.myTableTableAdapter.Fill(this.dataSet1.MyTable);
    this.SetCode();
}

this.myTableTableAdapter.Fillによって,全レコードがthis.dataSet1.MyTableオブジェクトに充填されます。 また,読みこまれたレコードは複数あるため,現在どのレコードを指しているのかに応じてCodeプロパティの値をセットするためのメソッドを呼び出します。

追加処理

bindingSource1のFindメソッドによって,番号列の値がthis.Codeプロパティの値を探して,その要素番号を取得しています。 bindingSource1オブジェクトはdataSet1.MyTableオブジェクトとバインドされているため,Fillメソッドによって充填したデータを参照できます。

要素番号が0以上なら,既に存在している値を追加しようとしていることになるため,例外エラーを発生させます。

public void Add() {
    this.InvalidCode();
    if (this.bindingSource1.Find("番号", this.Code) >= 0) {
        throw new Exception("既に登録されている番号です");
    }

    object newRow = this.bindingSource1.AddNew();
    DataSet1.MyTableRow row = this.GetMyTableRow(newRow);
    if (row == null) throw new Exception("追加に失敗しました");
    row.番号 = this.Code;

    this.bindingSource1.EndEdit();
    myTableTableAdapter.Update(this.dataSet1.MyTable);

    this.Read();
}

その後,新しい行をbindingSource1.AddNewメソッドから作成します。 作成された行オブジェクトはobject型なので,これをGetMyTableRowメソッドによってDataSet1.MyTableRow型に変換します。

最後に,bindingSource1のEndEditメソッドで編集を終了させて,dataSet1.MyTableオブジェクトの内容をデータベースに反映させます。

読み込み
this.bindingSource1.Position = i;

Positionプロパティに要素番号値を格納することで,現在指しているレコードを変更できます。

Codeプロパティに値をセットする

bindingSource1オブジェクトのCurrentプロパティは,現在指しているレコードオブジェクトを格納しています。

DataSet1.MyTableRow row = 
    this.GetMyTableRow(this.bindingSource1.Current);
if (row == null) {
    this.Code = 0;
    return;
}
this.Code = row.番号;

このレコードの番号の値をCodeプロパティにセットしています。

型の変換

以下は,指定されたオブジェクト型の値をDataSet1.MyTableRow型に変換した結果を返すためのメソッドです。 変換できない場合はnull値を返します。

private DataSet1.MyTableRow GetMyTableRow(object value) {
    DataRowView v = value as DataRowView;
    if (v == null) return null;

    return v.Row as DataSet1.MyTableRow;
}

C#はタイプセーフな言語です。

objectはすべての型から継承されている型なので,すべての変数はobject型に格納できます。

一方で,一度object型に格納したオブジェクトを元の型に代入するような場合には,キャスト(型変換)が必要です。

ただし,object型には何でも代入できてしまうため,確実にキャストできる保証はありません。 キャストに失敗すると,実行時に例外エラーが発生してしまいます。

DataRowView v = value as DataRowView;

上記のコードはas演算子を使って,valueをDataRowView型にキャストした結果をDataRowView型のvという変数に格納します。 この時,キャストに失敗した場合,vにはnullが格納されます。

著者プロフィール

伊藤達也(いとうたつや)

(株)井沢電器設備にて、業務管理システムの開発に従事しています。 この記事の趣旨通り、筆者自身が2005年後半にメインの開発言語をVB6からC#に移行し、2007年には Microsoft MVPアワードをC#で受賞しました。