C#

C# デフォルト引数について

「デフォルト引数」と呼ばれるメソッドの引数を省略した場合の「規定値」を指定できる記述方法があります。

下記の例の場合、引数の”data_type”を省略した場合、メソッド内でのdata_typeの値は0になる。という機能です。

public int GetData(int data_type = 0)

 

これは、C++ではよく知られる手法で、C#でもこの機能は使えるのですが、なぜか使える環境と使えない(?)環境があります。
今回は、画面などは使用しないので「コンソールアプリケーション」でプロジェクトを用意します。

まず、下記のような「デフォルト引数」を扱うメソッドを持つクラスを用意します。

サンプルコード(TestClass.cs)

public class TestClass
{
    private int _data;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public TestClass()
    {
        //
        _data = 1;
    }

    public int GetData(int data_type = 0)
    {
        if (data_type == 0)
        {
            return 0;
        }
        return _data;
    }
}

 

プロジェクトが自動生成してくれるProgram.csのMainメソッドに下記のような実装を行います。

class Program
{
    static void Main(string[] args)
    {
        TestClass obj = new TestClass();
        // TestClassのGetDataの戻り値が取れます。
        Console.WriteLine(string.Format("データの値(引数あり)={0}", obj.GetData(1)));
        // TestClassのGetDataの戻り値が取れます。
        Console.WriteLine(string.Format("データの値(引数なし)={0}", obj.GetData()));
    }
}

 

さて、このクラスをまず、Visual Studio 2010(2010以降であれば、基本的に同じ振る舞いになると思います。)で準備します。
Visual Studio 2010のプロジェクトの「対象のフレームワーク」で使用する.NET Frameworkのバージョンを3.5にして、ビルドします。

ビルドは通ります。そして、実行してみても、普通に動作します。

このコードを見る限り、Visual Studio 2010 でビルドも通っていますし、実行して結果が表示されますのでコードに問題はありません。

 

ところが・・・

「Visual Studio 2008」でコンソールアプリケーションのプロジェクトを作成して、このコードを入れると・・・
「ビルドエラー」でビルドすらできません。

作成したプロジェクトでも「対象のフレームワーク」は”.NET Framework 3.5″です。

エラーの内容は、

メソッドのほうが、「既定のパラメータ指定子は使用できません。」
呼び出し側のほうが、「引数を ‘0’ 個指定できる、メソッド ‘GetData’ のオーバーロードはありません。」

です。

 

なぜ Visual Studio 2008 と Visual Studio 2010 で挙動が違うのか

現段階ではっきりとした理由は不明なのですが、.NET Frameworkのバージョンの指定を同じにしていても
Visual Studioをインストールした時の「C#のバージョン」は Visual Studio 2008 と Visual Studio 2010 で異なります。

Visual Studio 2008 C# 3.0
Visual Studio 2010 C# 4.0

さらにこの「C# 4.0」で「オプション引数」が追加になっているのです。

 

対応(回避)策はどうするか

方法の一つは、デフォルト引数をやめて呼び出し側にすべて引数を与えるように(指定していなかったものはデフォルト値を指定すると同等の動きになります)変更する。
もう一つは、C++のお家芸ともいえる「オーバーロードを使う」です。

オーバーロードメソッドを追加する条件は、そのクラス自身が、自分で追加・変更が可能でなければなりません。

下記が、先ほどのTestClassクラスにオーバーロードメソッドを追加したサンプルです。

public class TestClass
{
    private int _data;

    /// <summary>
    /// コンストラクタ
    /// </summary>
    public TestClass()
    {
        //
        _data = 1;
    }

    /// <summary>
    /// オーバーロードしたメソッド
    /// </summary>
    /// <returns></returns>
    public int GetData()
    {
        return this.GetData(0);
    }

    //public int GetData(int data_type = 0)
    public int GetData(int data_type)
    {
        if (data_type == 0)
        {
            return 0;
        }
        return _data;
    }
}

 

デフォルト引数付きのメソッドは、デフォルト値を消して引数付きメソッドにします。
引数なしのメソッドを一つ追加し、そのメソッドが引数付きのメソッドを呼び出します。
このときの引数は「デフォルト値」になります。

 

タイトルとURLをコピーしました