95

C# 4.0 と C# 5.0 のスニーク プレビューについての Anders の講演を見ていて、C#でオプションのパラメーターがいつ利用可能になるかについて考えさせられました。

たとえば、FileStreamクラスのようなものには、論理的な「ファミリー」に分割できる約 15 の異なるコンストラクターがありIntPtrますSafeFileHandle

FileStream(string,FileMode);
FileStream(string,FileMode,FileAccess);
FileStream(string,FileMode,FileAccess,FileShare);
FileStream(string,FileMode,FileAccess,FileShare,int);
FileStream(string,FileMode,FileAccess,FileShare,int,bool);

このタイプのパターンは、代わりに 3 つのコンストラクターを用意し、デフォルト設定できるコンストラクターにオプションのパラメーターを使用することで単純化できるように思われます。これにより、コンストラクターのさまざまなファミリがより明確になります [注: この変更はBCLで作成された、私はこのタイプの状況について仮説的に話しています]。

どう思いますか?C# 4.0 から、密接に関連するコンストラクターとメソッドのグループをオプションのパラメーターを持つ単一のメソッドにすることはより理にかなっていますか?それとも、従来の多オーバーロード メカニズムに固執する正当な理由はありますか?

4

13 に答える 13

126

私は次のことを考えます:

  • オプションのパラメーターをサポートしていない言語からコードを使用する必要がありますか?その場合は、オーバーロードを含めることを検討してください。
  • オプションのパラメータに激しく反対するメンバーがチームにいますか?(場合によっては、ケースについて議論するよりも、気に入らない決定を下すほうが簡単な場合があります。)
  • コードのビルド間でデフォルトが変更されないことを確信していますか、または変更される可能性がある場合は、発信者はそれで問題ありませんか?

デフォルトがどのように機能するかは確認していませんが、constフィールドへの参照とほぼ同じように、デフォルト値が呼び出し元のコードに組み込まれると思います。それは通常は大丈夫です-とにかくデフォルト値への変更はかなり重要です-しかしそれらは考慮すべきことです。

于 2008-10-30T21:55:12.820 に答える
19

メソッドのオーバーロードが通常、異なる数の引数で同じことを実行する場合、デフォルトが使用されます。

メソッドのオーバーロードがそのパラメーターに基づいて異なる機能を実行する場合、オーバーロードは引き続き使用されます。

私はVB6の時代にオプションを使用していましたが、それを見逃してしまったため、C#でのXMLコメントの重複が大幅に減少します。

于 2008-10-30T21:47:37.377 に答える
11

私は、オプションのパラメーターを指定して Delphi をずっと使用してきました。代わりにオーバーロードを使用するように切り替えました。

より多くのオーバーロードを作成しようとすると、オプションのパラメーター形式と常に競合するため、とにかくそれらを非オプションに変換する必要があります。

そして、一般的に 1 つのスーパーメソッドがあり、残りはそのスーパー メソッドのより単純なラッパーであるという考えが気に入っています。

于 2009-06-24T16:55:56.270 に答える
7

私は間違いなく 4.0 のオプション パラメータ機能を使用します。それはばかげたものを取り除きます...

public void M1( string foo, string bar )
{
   // do that thang
}

public void M1( string foo )
{
  M1( foo, "bar default" ); // I have always hated this line of code specifically
}

...そして、呼び出し元が見える場所に値を配置します...

public void M1( string foo, string bar = "bar default" )
{
   // do that thang
}

はるかに単純で、エラーが発生しにくくなっています。私は実際にこれを過負荷の場合のバグとして見てきました...

public void M1( string foo )
{
   M2( foo, "bar default" );  // oops!  I meant M1!
}

私はまだ 4.0 コンパイラで遊んだことはありませんが、コンパイラが単純にオーバーロードを発行することを知っても驚かないでしょう。

于 2009-06-24T16:53:38.533 に答える
6

オプションのパラメーターは基本的に、メソッド呼び出しを処理しているコンパイラーに、呼び出しサイトに適切なデフォルトを挿入するように指示するメタデータの一部です。対照的に、オーバーロードは、コンパイラがいくつかのメソッドの 1 つを選択できる手段を提供します。メソッドの中には、デフォルト値自体を提供するものもあります。オプションのパラメータをサポートしていない言語で記述されたコードから、オプションのパラメータを指定するメソッドを呼び出そうとすると、コンパイラは「オプションの」パラメータを指定する必要があることに注意してください。ただし、オプションのパラメータを指定せずにメソッドを呼び出すと、デフォルト値に等しいパラメーターで呼び出すのと同じで、そのような言語がそのようなメソッドを呼び出すのに何の障害もありません。

呼び出しサイトでオプションのパラメーターをバインドすることの重要な結果は、コンパイラーが使用できるターゲット コードのバージョンに基づいて値が割り当てられることです。アセンブリに既定値が 5Fooのメソッドがあり、アセンブリに への呼び出しが含まれている場合、コンパイラはそれを として処理します。デフォルト値が 6 に変更され、アセンブリが再コンパイルされた場合、は、その新しいバージョンの で再コンパイルされない限り、または再コンパイルされるまで、呼び出しを続けます。したがって、変更される可能性のあるものに対してオプションのパラメーターを使用することは避ける必要があります。Boo(int)BarFoo.Boo()Foo.Boo(5)FooBarFoo.Boo(5)Foo

于 2013-01-21T01:41:51.757 に答える
5

オプションの引数またはオーバーロードを使用するかどうかは議論の余地がありますが、最も重要なことは、それぞれにかけがえのない独自の領域があることです。

オプションの引数は、名前付き引数と組み合わせて使用​​すると、COM 呼び出しのすべてがオプションの長い引数リストと組み合わせると非常に便利です。

オーバーロードは、メソッドが多くの異なる引数型 (例の 1 つにすぎません) を操作できる場合に非常に役立ちます。たとえば、内部でキャストを行います。意味のあるデータ型 (既存のオーバーロードで受け入れられるもの) をフィードするだけです。オプションの引数でそれを打ち負かすことはできません。

于 2010-05-21T10:16:13.147 に答える
4

オプション パラメーターの私のお気に入りの側面の 1 つは、メソッド定義に行かなくても、パラメーターを指定しない場合にパラメーターがどうなるかを確認できることです。メソッド名を入力すると、Visual Studio は単にパラメーターの既定値を表示します。オーバーロード メソッドを使用すると、(利用可能な場合でも) ドキュメントを読むか、メソッドの定義 (利用可能な場合) とオーバーロードがラップするメソッドに直接移動することになります。

特に、オーバーロードの量に応じて文書化の労力が急速に増加する可能性があり、既存のオーバーロードから既存のコメントをコピーすることになる可能性があります。これは、何の価値も生み出さず、DRY の原則に反するため、非常に面倒です)。一方、オプションのパラメーターを使用すると、すべてのパラメーターが文書化されている場所が1 か所だけあり、入力中にその意味とデフォルト値が表示されます。

大事なことを言い忘れましたが、あなたが API の消費者である場合、実装の詳細を検査するオプションさえないかもしれません (ソース コードがない場合)。ラッピングしています。したがって、ドキュメントを読んで、すべてのデフォルト値がそこにリストされていることを期待して立ち往生していますが、常にそうであるとは限りません.

もちろん、これはすべての側面を処理する答えではありませんが、これまでカバーされていないものを追加すると思います。

于 2016-03-08T08:12:44.893 に答える
3

デフォルトがメソッドに近いものを維持するので、オプションのパラメーターを楽しみにしています。したがって、「拡張」メソッドを呼び出すだけのオーバーロードの数十行の代わりに、メソッドを1回定義するだけで、オプションのパラメーターがメソッドシグネチャでデフォルトで何に設定されているかを確認できます。私はむしろ見たいです:

public Rectangle (Point start = Point.Zero, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

これの代わりに:

public Rectangle (Point start, int width, int height)
{
    Start = start;
    Width = width;
    Height = height;
}

public Rectangle (int width, int height) :
    this (Point.Zero, width, height)
{
}

明らかに、この例は本当に単純ですが、5つのオーバーロードがあるOPの場合、物事はすぐに混雑する可能性があります。

于 2008-10-30T21:51:09.600 に答える
1

これらは (おそらく?) API をゼロからモデル化するために利用できる 2 つの概念的に同等の方法ですが、残念ながら、実際の古いクライアントのランタイムの下位互換性を考慮する必要がある場合には、微妙な違いがあります。私の同僚 (Brent に感謝します!) は、この素晴らしい投稿を教えてくれました: Versioning issues with optional arguments。それからの引用:

そもそも C# 4 に省略可能なパラメーターが導入された理由は、COM 相互運用をサポートするためでした。それでおしまい。そして今、私たちはこの事実の完全な意味について学んでいます。オプションのパラメーターを持つメソッドがある場合、コンパイル時の重大な変更を引き起こす恐れがあるため、追加のオプションのパラメーターを含むオーバーロードを追加することはできません。また、これは常にランタイム破壊的変更であるため、既存のオーバーロードを削除することはできません。インターフェイスのように扱う必要があります。この場合の唯一の手段は、新しい名前で新しいメソッドを作成することです。したがって、API でオプションの引数を使用する予定がある場合は、この点に注意してください。

于 2016-09-14T19:58:34.620 に答える
0

Optional parameter 、 Method overload の両方には、独自の長所と短所があります。どちらを選択するかは、好みによって異なります。

オプションのパラメーター: .Net 4.0 でのみ使用できます。オプションのパラメーターを使用すると、コード サイズが縮小されます。out および ref パラメータを定義できません

オーバーロードされたメソッド: Out および ref パラメーターを定義できます。コードサイズは大きくなりますが、オーバーロードされたメソッドは理解しやすいです。

于 2012-12-31T07:27:37.957 に答える