簡體   English   中英

為什么要使用 params 關鍵字?

[英]Why use the params keyword?

我知道這是一個基本問題,但我找不到答案。

為什么要使用它? 如果你編寫了一個函數或一個使用它的方法,當你刪除它時,代碼仍然可以完美地工作,100% 沒有它。 例如:

帶參數:

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

沒有參數:

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

使用params您可以像這樣調用您的方法:

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

沒有params ,你不能。

此外,您可以在兩種情況下使用數組作為參數調用該方法:

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

也就是說, params允許您在調用方法時使用快捷方式。

無關,您可以大大縮短您的方法:

public static int addTwoEach(params int[] args)
{
    return args.Sum() + 2 * args.Length;
}

使用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 到無窮大變化時,可以使用數組。

它允許您根據需要在調用中添加任意數量的基本類型參​​數。

addTwoEach(10, 2, 4, 6)

而對於第二種形式,您必須使用數組作為參數

addTwoEach(new int[] {10,2,4,6})

params關鍵字的一個危險是,如果對方法的調用進行編碼之后,

  1. 有人意外/故意從方法簽名中刪除了一個/多個必需的參數,並且
  2. 一個/多個所需的參數之前立即params參數之前的簽名變化是類型兼容與params參數,

這些調用將繼續使用一個/多個先前用於必需參數的表達式進行編譯,這些表達式被視為可選的params參數。 我剛剛遇到了最糟糕的情況: params參數的類型為object[]

這是值得注意的,因為開發人員習慣於編譯器用更常見的場景拍打他們的手腕,其中參數從具有所有必需參數的方法中刪除(因為預期的參數數量會改變)。

對我來說,不值得走捷徑。 不帶params (Type)[]可以使用 0 到無窮大的參數,無需覆蓋。 最壞的情況是您必須在不適用的 Calls 中添加一個, new (Type) [] {}

順便說一句,恕我直言,最安全(也是最易讀的做法)是:

  1. 通過命名參數傳遞(我們現在甚至可以在C#做〜2個后,幾十年來我們可以在VB; P),這是因為:

    1.1. 這是確保防止在參數順序、兼容類型和/或調用已編碼后計數更改后傳遞給參數的意外值的唯一方法,

    1.2. 減少了參數含義更改后的機會,因為可能反映新含義的新標識符名稱就在傳遞給它的值旁邊,

    1.3. 它避免了必須計算逗號並從 Call to Signature 來回跳轉以查看為什么參數傳遞什么表達式,以及

    1.3.1. 順便說一句,僅僅因為這個原因應該是充足的(以避免頻繁出錯違反了DRY原則的只是閱讀代碼更何況還修改而言),但如果有一個這樣的原因可能是成倍更重要的/更多被傳遞的表達式本身包含逗號,即多維數組引用或多參數函數調用。 在這種情況下,您甚至不能使用(即使可以,仍然會每個方法調用的每個參數添加一個額外的步驟)在編輯器中的“選擇”功能中查找所有出現來為您自動進行逗號計數。

    1.4. 如果您必須使用可選參數(無論是否使用params ),它允許您搜索傳遞特定可選參數的調用(因此,很可能不是或至少有可能不是默認值),

(注意:原因 1.2. 和 1.3. 可以減輕和減少錯誤的機會,即使在對初始調用進行編碼時,更不用說何時必須讀取和/或更改調用。))

  1. 這樣做 ONE - PARAMETER - PER - LINE 以獲得更好的可讀性(因為:

    2.1. 它不那么雜亂,而且

    2.2. 它避免了向右和向左滾動(並且必須逐行這樣做,因為大多數人無法閱讀多行的左側部分,向右滾動並閱讀右側部分))。

    2.3. 它與我們已經為賦值語句演變成的“最佳實踐”一致,因為傳遞的每個參數本質上都是一個賦值語句(為局部變量賦值或引用)。 就像那些遵循 Coding Style最新“最佳實踐”的人不會夢想每行編碼多個賦值語句一樣,我們可能不應該(並且一旦“最佳實踐”趕上我的“天才”就不會;P ) 在傳遞參數時這樣做。

注意事項

  1. 在以下情況下傳遞名稱反映“參數”的變量無濟於事:

    1.1. 您正在傳遞文字常量(即簡單的 0/1、false/true 或 null,即使“最佳實踐”也可能不需要您使用命名常量,並且它們的目的不能輕易從方法名稱推斷出來),

    1.2. 該方法明顯低於調用者/更通用,因此您不希望/無法將您的變量命名為與參數相同/相似(或反之亦然),或

    1.3. 您正在重新排序/替換簽名中的參數,這可能導致先前的調用仍在編譯,因為類型碰巧仍然兼容。

  2. 擁有像 VS 這樣的自動換行功能只會消除我上面給出的 8 個原因中的一個(#2.2)。 在 VS 2015 之前,它沒有自動縮進(!?!真的,MS?!?)這增加了原因 #2.2 的嚴重性。

VS 應該有一個選項來生成帶有命名參數的方法調用片段(當然每行一個;P)和一個需要命名參數的編譯器選項(在概念上類似於 VB 中的 Option Explicit,順便說一句,這個要求曾經被認為是prolly同樣的離譜,但現在是prolly通過“‘最佳實踐’”)要求 事實上,“回到我的時代”;),在 1991 年我職業生涯剛剛開始的幾個月,甚至在我使用(或什至見過)帶有命名參數的語言之前,我就有反羊/“只是因為你可以,並不意味着你應該”/不要盲目地“切掉烤肉的末端”來模擬它(使用內嵌注釋)而沒有看到任何人這樣做。 不必使用命名參數(以及保存“'寶貴'”源代碼擊鍵的其他語法)是大多數這些語法開始時打卡時代的遺物。 有沒有借口,與現代的硬件和IDE的和更復雜的軟件,其中的可讀性是很多,很多,重要得多 “代碼的閱讀次數比編寫次數多得多”。 只要您不復制非自動更新的代碼,當有人(甚至您自己)稍后嘗試閱讀時,保存的每次擊鍵的成本可能會成倍增加。

無需創建重載方法,只需使用一個帶參數的方法,如下所示

// 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);

添加 params 關鍵字本身表明您可以在調用該方法時傳遞多個參數,這在不使用它的情況下是不可能的。 更加具體:

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

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

    return sum;
}

當您調用上述方法時,您可以通過以下任何一種方式調用它:

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

但是,當您刪除 params 關鍵字時,只有上述給定方式中的第三種方式才能正常工作。 對於第一種和第二種情況,您將收到錯誤消息。

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 }); . 在您可能需要傳入單個值而不是整個數組的情況下,這對於速記很有用。 它仍然在方法中以相同的方式處理,但為這種方式調用提供了一些糖果。

需要強調一件更重要的事情。 最好使用params因為它對性能更好。 當您使用params參數調用方法並沒有傳遞給它時:

public void ExampleMethod(params string[] args)
{
// do some stuff
}

稱呼:

ExampleMethod();

然后新版本的 .Net Framework 執行此操作(來自 .Net Framework 4.6):

ExampleMethod(Array.Empty<string>());

這個Array.Empty對象以后可以被框架重用,所以不需要做多余的分配。 當您像這樣調用此方法時,將發生這些分配:

 ExampleMethod(new string[] {});

可能聽起來很愚蠢,但 Params 不允許多維數組。 而您可以將多維數組傳遞給函數。

另一個例子

public IEnumerable<string> Tokenize(params string[] words)
{
  ...
}

var items = Tokenize(product.Name, product.FullName, product.Xyz)

它增強了簡潔性 當你可以很快的時候,為什么要傳統?

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);
        }
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM