357

I know this is a basic question, but I couldn't find an answer.

Why use it? if you write a function or a method that's using it, when you remove it the code will still work perfectly, 100% as without it. E.g:

With params:

static public int addTwoEach(params int[] args)
{
    int sum = 0;
    foreach (var item in args)
        sum += item + 2;
    return sum;
}

Without params:

static public int addTwoEach(int[] args)
{
    int sum = 0;
    foreach (var item in args)
       sum += item + 2;
    return sum;
}
4

11 に答える 11

508

With params you can call your method like this:

addTwoEach(1, 2, 3, 4, 5);

Without params, you can’t.

Additionally, you can call the method with an array as a parameter in both cases:

addTwoEach(new int[] { 1, 2, 3, 4, 5 });

That is, params allows you to use a shortcut when calling the method.

Unrelated, you can drastically shorten your method:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}
于 2011-09-28T08:24:23.890 に答える
101

を使用paramsすると、引数なしで関数を呼び出すことができます。なしparams

static public int addTwoEach(int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // throws an error

と比較してくださいparams

static public int addTwoEach(params int[] args)
{
    int sum = 0;

    foreach (var item in args)
    {
        sum += item + 2;
    }

    return sum;
}

addtwoEach(); // returns 0

一般に、引数の数が0から無限大まで変化する場合はparamsを使用でき、引数の数が1から無限大まで変化する場合は配列を使用できます。

于 2011-09-28T09:05:13.717 に答える
22

これにより、呼び出しに必要な数の基本タイプのパラメーターを追加できます。

addTwoEach(10, 2, 4, 6)

一方、2番目の形式では、パラメーターとして配列を使用する必要があります

addTwoEach(new int[] {10,2,4,6})
于 2011-09-28T08:26:06.013 に答える
21

paramsKeywordの危険性の 1 つは、メソッドの呼び出しがコーディングされた後に、

  1. 誰かが誤って/故意にメソッド シグネチャから1 つまたは複数の必要なパラメーターを削除した場合、および
  2. 署名の変更前のパラメーターの直前にある 1 つ以上の必須パラメーターは、パラメーターparamsと型互換性がありました。params

これらの呼び出しは、オプションのパラメーターとして扱われる必要なパラメーターに対して以前に意図された 1 つまたは複数の式でコンパイルを続行しますparams。これの最悪のケースに遭遇しました: paramsParameter は Typeobject[]でした。

開発者は、必要なすべてのパラメーターを含むメソッドからパラメーターが削除されるという、はるかに一般的なシナリオでコンパイラーが手首を叩くことに慣れているため、これは注目に値します(予期されるパラメーターの数が変わるため)。

私にとって、近道をする価値はありません。 (Type)[]withoutparamsは、オーバーライドを必要とせずに、0 から無限の数のパラメーターで動作します。最悪の場合, new (Type) [] {}、それが適用されない呼び出しに a を追加する必要があります。

ところで、最も安全な(そして最も読みやすい慣行)は次のとおりです。

  1. 名前付きパラメータを介して渡します(これは、VB ;P でできてから約20 年後に C#でもできるようになりました)。理由は次のとおりです。

    1.1。呼び出しがコーディングされた後、パラメーターの順序、互換性のあるタイプ、および/またはカウントの変更後にパラメーターに渡される意図しない値の防止を保証する唯一の方法です。

    1.2. 新しい意味を反映している可能性が高い新しい識別子名は、渡される値のすぐ隣にあるため、パラメーターの意味が変更された後のこれらの可能性を減らします。

    1.3。どのパラメーターに対してどの式が渡されているかを確認するために、カンマを数えたり、Call から Signature に前後にジャンプしたりする必要がなくなります。

    1.3.1. ちなみに、この理由だけでも十分なはずです (コードを読むだけでなく、コードを変更するためだけにエラーが発生しやすい DRY 原則の頻繁な違反を回避するという観点から)が、この理由は、1 つ/それ自体がコンマを含む式が渡されます。つまり、多次元配列参照または多パラメータ関数呼び出しです。その場合、コンマカウントを自動化するために、エディターの選択機能ですべてのオカレンスを検索する機能を使用することさえできませんでした (使用できたとしても、メソッド呼び出しごとにパラメーターごとに追加のステップを追加することになります)

    1.4。オプションのパラメーターを使用する必要がある場合 (paramsまたは使用しない場合)、特定のオプションのパラメーターが渡される呼び出しを検索できます (したがって、ほとんどの場合、デフォルト値ではないか、少なくともデフォルト値ではない可能性があります)。

(注: 理由 1.2. および 1.3. は、呼び出しを読み取ったり変更したりする必要がある場合は言うまでもなく、最初の呼び出しをコーディングする場合でも、エラーの可能性を軽減および削減できます。))

  1. 読みやすくするために、ONE - PARAMETER - PER - LINE のようにします (理由:

    2.1. 散らかりにくく、

    2.2. 右にスクロールして左に戻る必要がなくなります(ほとんどの人間は複数行の左部分を読むことができず、右にスクロールして右部分を読むことができないため、行ごとにそうする必要があります)。

    2.3. 渡されたすべてのパラメーターは本質的に代入ステートメント (ローカル変数への値または参照の代入) であるため、代入ステートメント用に既に進化してきた "ベスト プラクティス" と一致しています。コーディング スタイルの最新の「ベスト プラクティス」に従う人が1 行に複数の割り当てステートメントをコーディングすることを夢にも思わないのと同じように、おそらくそうすべきではありません (そして、「ベスト プラクティス」が私の「天才」に追いつくことはありません ;P ) パラメータを渡すときにそうします。

:

  1. 名前がパラメーターを反映する変数を渡すことは、次の場合には役に立ちません。

    1.1。リテラル定数 (つまり、単純な 0/1、false/true または null を渡しているため、「ベスト プラクティス」でも名前付き定数を使用する必要がない場合があり、その目的はメソッド名から簡単に推測できません) )、

    1.2. メソッドが Caller よりも大幅に低レベル/より一般的であるため、変数にパラメーターと同じ/類似の名前を付けたくない/できない (またはその逆)、または

    1.3。タイプがたまたま互換性があるため、以前の呼び出しがまだコンパイルされている可能性がある署名のパラメーターを並べ替え/置換しています。

  2. VS のような自動ラップ機能を使用しても、上記の 8 つの理由のうち 1 つ (#2.2) が解消されるだけです。VS 2015 までは自動インデント (!?! 本当に、MS ?!?) を行わなかったため、理由 #2.2 の深刻度が増しました。

VSには、名前付きパラメーター(もちろん1行に1つ; P)を使用してメソッド呼び出しスニペットを生成するオプションと、名前付きパラメーターを必要とするコンパイラオプションが必要です(VBのOption Explicitと概念が似ています。同様にとんでもないことですが、現在は「ベスト プラクティス」でかなり要求されています)。実際、「私の中に戻っ;)、1991 年、キャリアを始めてわずか数か月で、名前付きパラメーターを使用する言語を使用する前 (または見たこともない) でさえ、私は反対意見を持っていました。 / やみくもに "ローストの端を切る" 感覚をシミュレートするのに十分 (インライン コメントを使用して) 誰かがそうしているのを見たことがない.名前付きパラメーターを使用する必要がない ("'貴重な'"ソース コードのキーストローク) は、これらの構文のほとんどが始まったパンチ カード時代の遺物です. ​​現代のハードウェアと IDE と、可読性が非常に高いはるかに複雑なソフトウェアでは、その言い訳はできませんより重要。「コードは書かれるよりも読まれることが多い」. 自動更新されていないコードを複製しない限り、保存されたすべてのキーストロークは、後で誰かが (自分自身でさえも) 読み取ろうとすると、指数関数的に多くのコストがかかる可能性があります。

于 2015-06-30T18:05:32.077 に答える
10

オーバーロード メソッドを作成する必要はありません。以下に示すように、params を含む 1 つのメソッドを使用するだけです。

// Call params method with one to four integer constant parameters.
//
int sum0 = addTwoEach();
int sum1 = addTwoEach(1);
int sum2 = addTwoEach(1, 2);
int sum3 = addTwoEach(3, 3, 3);
int sum4 = addTwoEach(2, 2, 2, 2);
于 2014-03-31T07:43:42.140 に答える
5

params単一の引数でメソッドを呼び出すこともできます。

private static int Foo(params int[] args) {
    int retVal = 0;
    Array.ForEach(args, (i) => retVal += i);
    return retVal;
}

すなわちFoo(1);の代わりにFoo(new int[] { 1 });。配列全体ではなく単一の値を渡す必要があるシナリオで、省略表現に役立ちます。メソッド内で同じ方法で処理されますが、この方法で呼び出すと、いくつかのキャンディーが得られます。

于 2011-09-28T08:55:44.317 に答える
0

簡潔さを向上させます。あなたが速くできるのに、なぜ慣習的である必要がありますか?

using System;

namespace testingParams
{
    class Program
    {
        private void canOnlyBeCalledSlowly(int[] myArr)
        {
            Console.WriteLine("Snore");
        }
        private void canBeCalledQuickly(params int[] myArr) {
            Console.WriteLine("That was quick");
        }

        static void Main(string[] args)
        {
            Program p = new Program();
            //We're being conventional here:
            int[] myArr = new int[] { 1, 2, 3, 4, 5 };
            p.canOnlyBeCalledSlowly(myArr);
            //We're being quick here:
            p.canBeCalledQuickly(1, 2, 3);
        }
    }
}
于 2021-05-01T23:46:28.030 に答える