Java プログラマのための C# 入門 (#3 クラス定義の基本とメソッド)

#2 配列と文字列」 に引き続き、今回は C# のクラス定義の基本とメソッドのパラメータについて Java との違いをメモしておきます。 参考にしている書籍は 『独習 C#』 です。

C# のクラスに関して、フィールドやメソッド、コンストラクタについてはほとんど Java と同じですが、インデクサやプロパティといった Java にはないものも定義できます。 また、メソッドに関して、パラメータを参照渡しにしたり、可変個数のパラメータを受け取るようにすることもできます。 今回はクラス定義の基本と、パラメータの参照渡しや可変個数のパラメータを受け取るメソッドの定義について。 インデクサやプロパティなどについてはまた次回書きます。

クラス定義の基本

インスタンス変数 (インスタンスフィールド) や静的変数 (クラスフィールド)、メソッドなどの定義の方法は基本的に Java と同じです。 アクセス修飾子を省略した場合に private になる ところが Java と違うので注意が必要です。 (Java のようなパッケージプライベートは存在しない。)

コンストラクタの定義も基本的には Java と同じですが、オーバーロードされた別のコンストラクタを呼び出す方法が異なります。 また、Java にはオブジェクトがガベージコレクトされる際に実行されるメソッドとして finalize メソッドがありますが、C# ではデストラクタがその役割を果たします。

クラスがロードされた際に実行される処理は、static コンストラクタに記述します。 これは Java の static ブロックに相当するものと思えば良いと思います。

class C {

    // アクセス修飾子は public, protected, private, internal を指定できる
    // 省略した場合は private
    // (internal はアセンブリの使い方と関係している)

    // インスタンス変数
    int InstVal;

    // 静的変数
    static int ClassVal = 200;

    // インスタンスメソッド
    public void InstMeth() {
        Console.WriteLine(InstVal);
    }
    // インスタンスメソッドのオーバーロード
    public void InstMeth( string msg ) {
        Console.WriteLine( msg + ": " + InstVal );
    }

    // 静的メソッド
    public static void ClassMeth() {
        Console.WriteLine( ClassVal );
    }

    // コンストラクタ
    public C( int val ) {
        InstVal = val;
        Console.WriteLine( "a C object constructed" );
    }
    // 自身の別のコンストラクタを呼び出すときには, コロンの後ろに this( 引数 ) の形式
    public C() : this( 10 ) {}

    // デストラクタ (ガベージコレクションで破棄される直前に呼び出される)
    ~C(){
        Console.WriteLine( "a C object destructed" );
    }

    // 静的コンストラクタ
    // Java でいうところの static ブロック. クラスロード時に実行
    static C() {
        Console.WriteLine( "the C class loaded" );
    }

}

静的クラス

C# 2.0 からは静的クラスを定義できます。 class キーワードの前に static キーワードを付けます。 静的クラスには静的メンバーしか定義できず、静的クラスをインスタンス化することもできません。

参照パラメータと出力パラメータ

Java では参照渡しを行うことができませんが、C# では参照渡しができます。 メソッドのパラメータに ref キーワードを付けると参照パラメータになり、参照渡しされます。

参照パラメータとしてメソッドに渡す変数は、初期化済みでなければいけません。 しかし、場合によっては初期化されていない変数をメソッドに参照渡しして、メソッドの中で変数に値を代入する、ということをしたい場合もあります。 そのために使われるのが出力パラメータです。 出力パラメータは、メソッドのパラメータに out キーワードを付けて宣言します。 出力パラメータとして、未初期化の変数が渡される可能性があるため、メソッドの中で値を割り付けるまでは出力パラメータを使用することはできません。 また、メソッドを抜けるまでに値を割り付ける必要があります。

class CC {
    // 参照パラメータと出力パラメータ
    public static void RefOutTest( ref int r, out int o ) {
        // 参照パラメータは利用できる
        Console.WriteLine( r + 200 );
        // 出力パラメータは利用できない
        //Console.WriteLine( o + 200 );
     
        // 参照パラメータに代入すると呼び出し元の変数に影響を与える
        r = 100;
        // 出力パラメータに代入すると呼び出し元の変数に影響を与える
        o = 200; // メソッド終了前に出力パラメータに値を代入しなければならない
    }
}

参照パラメータや出力パラメータを受け取るメソッドを呼び出す際には、呼び出し側でも ref キーワードや out キーワードをつける必要があります。

int a = 10, b;
CC.RefOutTest( ref a, out b ); // 出力パラメータとして受け取られる b は未割り当てでも良い

ref キーワードや out キーワードも付けたメソッドのシグニチャの一部なので、これらのキーワードを付けたメソッドと付けていないメソッドのオーバーロードが可能です。

可変長引数

可変個数の引数を受け取るメソッドを定義できます。 可変個数の引数を受け取るためのパラメータをパラメータ配列といい、params 修飾子を付けた配列パラメータとして宣言します。 Java と同じように、可変個数の引数を受け取るパラメータはメソッドにつき 1 つしか使えません。 また、パラメータのリストの中の一番最後に置く必要があります。 パラメータ配列は 0 個以上の引数を受け取るため、0 個の引数を受け取る可能性もあります。

class CParams {
    // 可変長引数を受け取るメソッド
    public int Min( int v, params int[] vals ) {
        foreach ( int val in vals ) {
            v = Math.Min( v, val );
        }
        return v;
    }
}

呼び出し時は特に特殊なことはせずに呼び出せます。

int min = CParams.Min( 20, 10, 4, 30 );

参考文献