[英]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
關鍵字的一個危險是,如果在對方法的調用進行編碼之后,
params
參數之前的簽名變化是類型兼容與params
參數, 這些調用將繼續使用一個/多個先前用於必需參數的表達式進行編譯,這些表達式被視為可選的params
參數。 我剛剛遇到了最糟糕的情況: params
參數的類型為object[]
。
這是值得注意的,因為開發人員習慣於編譯器用更常見的場景拍打他們的手腕,其中參數從具有所有必需參數的方法中刪除(因為預期的參數數量會改變)。
對我來說,不值得走捷徑。 不帶params
(Type)[]
可以使用 0 到無窮大的參數,無需覆蓋。 最壞的情況是您必須在不適用的 Calls 中添加一個, new (Type) [] {}
。
順便說一句,恕我直言,最安全(也是最易讀的做法)是:
通過命名參數傳遞(我們現在甚至可以在C#做〜2個后,幾十年來我們可以在VB; P),這是因為:
1.1. 這是確保防止在參數順序、兼容類型和/或調用已編碼后計數更改后傳遞給參數的意外值的唯一方法,
1.2. 它減少了參數含義更改后的機會,因為可能反映新含義的新標識符名稱就在傳遞給它的值旁邊,
1.3. 它避免了必須計算逗號並從 Call to Signature 來回跳轉以查看為什么參數傳遞什么表達式,以及
1.3.1. 順便說一句,僅僅因為這個原因應該是充足的(以避免頻繁出錯違反了DRY原則的只是閱讀代碼更何況還修改而言),但如果有一個這樣的原因可能是成倍更重要的/更多被傳遞的表達式本身包含逗號,即多維數組引用或多參數函數調用。 在這種情況下,您甚至不能使用(即使可以,仍然會為每個方法調用的每個參數添加一個額外的步驟)在編輯器中的“選擇”功能中查找所有出現來為您自動進行逗號計數。
1.4. 如果您必須使用可選參數(無論是否使用params
),它允許您搜索傳遞特定可選參數的調用(因此,很可能不是或至少有可能不是默認值),
(注意:原因 1.2. 和 1.3. 可以減輕和減少錯誤的機會,即使在對初始調用進行編碼時,更不用說何時必須讀取和/或更改調用。))
和
這樣做 ONE - PARAMETER - PER - LINE 以獲得更好的可讀性(因為:
2.1. 它不那么雜亂,而且
2.2. 它避免了向右和向左滾動(並且必須逐行這樣做,因為大多數人無法閱讀多行的左側部分,向右滾動並閱讀右側部分))。
2.3. 它與我們已經為賦值語句演變成的“最佳實踐”一致,因為傳遞的每個參數本質上都是一個賦值語句(為局部變量賦值或引用)。 就像那些遵循 Coding Style最新“最佳實踐”的人不會夢想每行編碼多個賦值語句一樣,我們可能不應該(並且一旦“最佳實踐”趕上我的“天才”就不會;P ) 在傳遞參數時這樣做。
注意事項:
在以下情況下傳遞名稱反映“參數”的變量無濟於事:
1.1. 您正在傳遞文字常量(即簡單的 0/1、false/true 或 null,即使“最佳實踐”也可能不需要您使用命名常量,並且它們的目的不能輕易從方法名稱推斷出來),
1.2. 該方法明顯低於調用者/更通用,因此您不希望/無法將您的變量命名為與參數相同/相似(或反之亦然),或
1.3. 您正在重新排序/替換簽名中的參數,這可能導致先前的調用仍在編譯,因為類型碰巧仍然兼容。
擁有像 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;
}
當您調用上述方法時,您可以通過以下任何一種方式調用它:
addTwoEach()
addTwoEach(1)
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.