web-dev-qa-db-ja.com

C#のオプションのパラメータまたはメソッドのオーバーロード?

C#はオプションのパラメーターを追加したので、オプションのパラメーターまたはメソッドのオーバーロードを使用することをお勧めします。または、一方を他方の上に使用したい特定のケースがあります。つまり、パラメータがたくさんある関数は、オプションのパラメータがある方が適していますか?

24
Luke Belbina

オプションのパラメータはNiceですが、意味がある場合に使用する必要があります。オプションのパラメータは、メソッドの意図を混乱させることがよくあります-別の選択肢がある場合、私はその選択肢に傾倒します。

オプションのパラメーターと名前付きパラメーターの必要性の一部は、COMがオプションのパラメーターと名前のパラメーターを許可したためです。

[〜#〜] msdn [〜#〜]

一部のAPI、特にOfficeオートメーションAPIなどのCOMインターフェイスは、名前付きパラメーターとオプションのパラメーターを念頭に置いて特別に作成されています。これまで、C#からこれらのAPIを呼び出すのは非常に面倒で、30もの引数を明示的に渡す必要があり、そのほとんどは妥当なデフォルト値を持っているため、省略できます。

Forums.asp.netのSomeNewKidは簡潔に次のように述べています。

http://forums.asp.net/t/386604.aspx/1

...オーバーロードされたメソッドは、一般的にオプションのパラメータよりも望ましいです。どうして?それぞれの方法を目的を明確に保つため。つまり、それぞれの方法で1つのことがうまくいくはずです。オプションのパラメータを導入するとすぐに、そのメソッドのクリーンさが薄れ、メソッドから除外するのがおそらく最善の分岐ロジックが導入されます。継承を使い始めると、この目的の明確さがさらに重要になります。 1つ以上のオプションのパラメーターを持つメソッドをオーバーライドすると、それらの操作が難しくなります。したがって、クイッククラスとダーティクラス以外の場合は、オプションのパラメーターよりもオーバーロードを使用することをお勧めします。

オプションのパラメーターは構文上の糖衣構文であることに注意してください。

リフレクターC#:

public class Class1
{
    // Methods
    public Class1()
    {
        this.Method1("3", "23");
    }

    public void Method1(string one, [Optional, DefaultParameterValue("23")] string two)
    {
    }
}

IL:

.class public auto ansi beforefieldinit Class1
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: nop 
        L_0007: nop 
        L_0008: ldarg.0 
        L_0009: ldstr "3"
        L_000e: ldstr "23"
        L_0013: call instance void WebApplication1.Class1::Method1(string, string)
        L_0018: nop 
        L_0019: nop 
        L_001a: ret 
    }

    .method public hidebysig instance void Method1(string one, [opt] string two) cil managed
    {
        .param [2] = string('23')
        .maxstack 8
        L_0000: nop 
        L_0001: ret 
    }

}
21
Chuck Conway

Visual StudioおよびFxCopのコード分析では、パブリックAPIでオプションの引数を使用しないことをお勧めします(ルール CA1026:デフォルトのパラメーターは使用しないでください )。与えられた理由は、すべての.NET言語がそれらをサポートしているわけではないからです。

ただし、これらを回避するより良い理由は、APIのバージョン2.0でオーバーロードを追加すると、ランタイムまたはコンパイル時の問題が発生する可能性があるためです。 Phil Haackがここで説明しています

Philの結論を採用します。オプションのパラメーターは、COM相互運用機能をサポートするように設計されています。 COMを使用していない場合は、そのままにしておきます。

12
Rory MacLeod

これに対する標準的な答えがあるかどうかはわかりません-それは主観的でケースバイケースです。ただし、私の意見では、オプションのパラメーターはより明示的なAPIを作成するため、通常、メソッドのオーバーロードよりもAPIを優先します。

具体的には、Intellisenseを使用する場合、私はこれを見たいと思っています。

optional params with defaults

これ以上:

overload 1

overload 2

overload 3

指定しない場合、param1とparam2の値がどうなるかを推測(またはドキュメントを検索)する必要がある場合があります。

10
hemp

オプションパラメータは、COMオブジェクトが多くのオプションパラメータを使用するため、COMオブジェクトの相互作用を容易にすることを目的としています。したがって、P/InvokeまたはCOMオブジェクトを実行している場合は、オプションのパラメーターを選択してください。それ以外の場合は、メソッドのオーバーロードが適切な方法であり、多くの混乱を回避できます。

4
Teoman Soygul

オーバーロードしたり、オプションのパラメーターに名前を付けたりするのではなく、オブジェクト初期化子が大好きになりました。クラスに必要なのは、パラメーターのないコンストラクターと、初期化時に設定するすべてのパブリックプロパティです。

クラスBarにパブリック文字列プロパティ「Name」と「Pet」があると仮定すると、このような新しいオブジェクトを作成できます。

var foo = new Bar { Name = "Fred", Pet = "Dino" };

利点は、初期化する値の組み合わせごとに個別のオーバーロードが必要ないことです。

4
Cylon Cat