無制限のパラメーターを持つc#メソッドまたは配列またはリストを持つメソッド?


21

私は最近、無制限のパラメーターを使用していくつかのメソッドを作成できることを学びました。次に例を示します。

SomeMethod(params int[] numbers);

しかし、私の質問は、それとリストまたは配列を受け取るメソッドを作成することの違いは何ですか?

SomeMethod(int[] numbers);
SomeMethod(List<int> numbers);

おそらくそれはパフォーマンスに何らかの影響を与えますか?無制限のパラメーターを使用する方法をどのように選択すればよいのか、完全に理解または確認していません。

グーグルでのクイック検索は役に立たなかった、あなたが私を助けてくれるといいのですが。



以下の私の答えに加えて、引数の型paramsも配列である必要があります。配列以外のコレクションを使用する必要がある場合は、params代わりに非引数を指定する方が理にかなっています。
digitlworld

1
@digitlworld:このテーマに興味がある場合は、github.com / dotnet / csharplang / issues / 179を参照してください。
エリックリッペルト

の署名や実装を確認してくださいConsole.Write
3Dave

回答:


27

それとリストまたは配列を受け取るメソッドを作成することの違いは何ですか?

の違い

void M(params int[] x)

そして

void N(int[] x)

Mは次のように呼び出されるということです:

M(1, 2, 3)

またはこのように:

M(new int[] { 1, 2, 3 });

しかし、Nは最初の方法ではなく、2番目の方法でのみ呼び出すことができます。

おそらくそれはパフォーマンスに何らかの影響を与えますか?

パフォーマンスへの影響Mは、最初の方法で呼び出すか、2番目の方法で呼び出すか、どちらの方法で配列を作成するかです。アレイを作成すると、時間とメモリの両方が必要になるため、パフォーマンスに影響があります。パフォーマンスへの影響は、パフォーマンスの目標に対して測定する必要があることに注意してください。追加のアレイを作成するコストが、市場での成功と失敗の違いであるゲーティング要因であるとは考えられません。

無制限のパラメーターを使用する方法をどのように選択すればよいのか、完全に理解または確認していません。

これは、メソッドを呼び出すコードの作成者にとって純粋かつ完全に便利です。それは単に短くて書くのが簡単です

M(1, 2, 3);

書く代わりに

M(new int[] { 1, 2, 3 });

発信者側のいくつかのキーストロークを節約するだけです。以上です。

尋ねなかったが、おそらくその答えを知りたいいくつかの質問:

この機能は何と呼ばれていますか?

呼び出し側で可変数の引数を渡すことができるメソッドは、可変引数と呼ばれます。Paramsメソッドは、C#が可変メソッドを実装する方法です。

オーバーロードの解決は、可変長メソッドでどのように機能しますか?

過負荷の解決の問題に直面した場合、C#は「通常の」フォームと「拡張された」フォームの両方を考慮します。両方が当てはまる場合、「通常の」フォームが常に優先されます。たとえば、次のことを考慮してください。

void P(params object[] x){}

そして、私たちは電話をしています

P(null);

2つの適用可能な可能性があります。「通常の」形式ではP、配列のnull参照を呼び出して渡します。「拡張された」形式では、と呼びますP(new object[] { null })。この場合、通常の形式が優先されます。呼び出しがあった場合P(null, null)、通常のフォームは適用できず、拡張されたフォームがデフォルトで優先されます。

課題:私たちがvar s = new[] { "hello" };電話しているとしますP(s);。呼び出しサイトで何が発生し、その理由を説明してください。びっくりするかも!

課題:との両方があるvoid P(object x){}としvoid P(params object[] x){}ます。何をするのP(null)か、そしてその理由は?

課題:との両方があるvoid M(string x){}としvoid M(params string[] x){}ます。何をするのM(null)か、そしてその理由は?これは前のケースとどう違うのですか?


CH2:P(null)P((object)null)P((object[])null)-どこ私はこの違いの説明を見つけることができますか?それは感じているようnullだったいくつかの特殊なタイプの配列ではなく、オブジェクト(への変換、P(null)文字列または曖昧な文字列(の配列への変換を見つける。)が、M(null)非常に奇妙な感じ)...、それはどちらかの両方のケースで曖昧であるか選ぶことを期待します単一引数バージョン(そうではありません)。しかし、それはC ++テンプレートのユニバーサル参照()のように、params何らかの形で一般的であることがより重要&&であり、したがって(Ch3ではなくCh2で)よりよく一致していると思います。
firda

@firda:説明はC#仕様にあります。この奇妙な理由は、nullがオブジェクト、文字列、オブジェクト[]および文字列[]に変換できることです。したがって、オーバーロードの解決に提起される質問は、どの変換が最適ですか?この場合の制御ルールは、一般的なものよりも具体的な方が優れています。どのタイプがより具体的であるかをどのように見分けるのですか?ルールは次のとおりです。すべてのキリンは動物ですが、すべての動物がキリンであるとは限らないため、キリンは動物よりも具体的です。すべてはobject[]あるobjectが、すべてではないobjectですobject[]ので、object[]より具体的です。
Eric Lippert

@firda:これで、文字列があいまいになる理由がわかりました。「すべてある」というのstring[]は本当ではありませんstring。実際、NO string[]はNOでありstring、NO stringはIS ですstring[]。したがって、stringより具体的でも一般的でもありませんstring[]。選択を求められた場合、あいまいなエラーが発生します。
Eric Lippert

All object[]are object... object[]はより具体的であるためP(null)、より具体的な配列thxについては、それが欠けていました。ここで見つけるいくつかのルール:docs.microsoft.com/en-us/dotnet/csharp/language-reference/...
firda

5

ちょっとプロトタイプを作っただけです。答えparamsは、配列を渡すための単純な構文糖であると思われます。それは本当に驚きではありません。同じメソッドの2つのバージョンを作成しましたが、唯一の違いは「params」キーワードです。両方に対して生成されたILはSystem.ParamArrayAttributeparamsバージョンにa が適用されたことを除いて、同一でした。

さらに、呼び出しサイトで生成されたILも、手動で宣言new int[]してメソッドを呼び出す場合と、params引数を使用してメソッドを呼び出す場合とで同じでした。

だから、答えは「便利さ」のようです。パフォーマンスに違いはないようです。params代わりに配列を使用して関数を呼び出すこともできるので、これもそれほど驚くべきことではありません。これは、メソッドのコンシューマが、someMethod(1, 2, 3)常に最初にコレクションを作成する必要がある(例:)よりも、任意の数のパラメータ(例:)でそれを呼び出す方が簡単かどうかに依存しますsomeMethod(new List<int>() { 1, 2, 3 } )


4

無制限パラメーターの機能は、多くのシナリオで以下の利点を提供します。

  1. 疎結合
  2. 強化された再利用性
  3. アプリケーションの全体的なパフォーマンスが向上

これは、無制限のパラメーターオプションが最適な例です。

電子メールを送信するためのアプリケーションを構築する必要があることを考慮してください。

Eメールを送信する関数は、「宛先」、「CC」、および「BCC」フィールドの単一または複数の値を処理できる必要があります。

パラメーターのタイプがすべてのフィールド(To、CC、BCC)の配列またはリストに固定されている場合、呼び出し側関数は、Eメール送信者関数を呼び出すために3つの配列またはリストを定義するすべての複雑さを処理する必要があります。 。

発信者が1つのアドレスにのみメールを送信したい場合でも、メール送信機能は、発信者にパラメータとして3つの異なる配列を定義して送信するように強制します。

電子メール送信者関数が無制限のパラメーターアプローチを取る場合、呼び出し側関数はすべての複雑さを処理する必要はありません。

無制限のパラメーターアプローチは、不必要な場所での配列やリストの作成を回避することで、アプリケーションの実行時のパフォーマンスを向上させます。


2

非パフォーマンス、スタイルの視点、paramsキーワードを使用すると、パラメータのオプションのリストを送信したい時に持っていることは本当に素晴らしいです。

個人的にはparams、私のコードが次のようなものだったときに使用します

SomeMethod('Option1', 'Option17');

void SomeMethod(params string[] options)
{
    foreach(var option in options)
    {
        switch(option): ...
    }
}

これの良い点は、毎回配列やリストを作成する必要なしに、このメソッドをどこでも使用できることです。

私は使用するarraylist、常にこの関数に、すでにまとめられている一連のデータを常にこの関数に渡します

List<User> users = GetUsersFromDB();
SomeMethod(users);

それがもたらすparams柔軟性にメリットがあると思います。コードへの影響は比較的小さいかもしれませんが、それでも優れたツールです。


1

呼び出し規約は異なります。例えば ​​...

public class Test
{
    public void Method1( params int[] nums )
    {
        nums.ToList().ForEach( n => Console.WriteLine(n) );
    }

    public void Method2( List<int> nums )
    {
        nums.ForEach( n  => Console.WriteLine(n) );
    }   
}

void Main()
{   
    var t = new Test();
    t.Method1( 1, 2, 3, 4 );
    t.Method2( new List<int>() { 1, 2, 3, 4 } );
}

最初のケースでは、個別のパラメーターと同じ数のintをメソッドに渡すことができます。2番目では、リストをインスタンス化して渡す必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.