2015-06-20 70 views
0

我發現C#中的這個特性「命名參數」非常奇怪,因爲我發現它有兩個缺陷。書上說的「命名參數給你‘來傳遞參數以任意順序的能力’使用C#「命名參數」的實際原因

兩個缺點,我認爲是這個C#功能的一個問題:

  1. 它違反了‘信息隱藏’在計算機科學 (即:使用該方法的最終用戶需要知道參數名稱和數據類型才能使用該功能)。從Java背景來看,這很奇怪。爲什麼要將參數名稱展示給用戶的最後?

  2. 它容易產生歧義,可能導致錯誤 (程序當程序員編寫使用相同方法名稱的方法(又稱重載方法)時,ammer需要做額外的思考和問題。你總是會得到一個「調用是模棱兩可的,當你有兩個相同名稱的方法時,即使另一個方法有不同數據類型的額外參數,我們可以想到的唯一的修復方法是使數據沒有默認值鍵入「強制參數」又名一個參數,這樣編譯器不會混淆。但後來此修復程序只是一個繃帶解決導致另一個最壞的情況(見下文)

做的人在行業中甚至會使用這個概念到現在呢?如果是這樣,爲什麼打破兩個規則給予「調用方法時按任意順序傳遞參數的能力」?

TLDR:一個例子,以澄清什麼我是 通過引入一個可能的最壞的情況下談論(編譯器選擇了錯誤的方法調用......儘管這兩種方法的相似):

namespace ConsoleApplication1 
{ 
    class Venusaur 
    { 
     static void Main(string[] args) 
     { 

      new Venusaur().optMethod(fourth: "s"); 
     } 

     public void optMethod( string third , string fourth = "hello", int fifth = 23, string two = "w") 
     { 
      // what if I wanted this method to run instead of the method below me 
      Console.WriteLine("did not execute"); 
     } 


     public void optMethod(string third = "Byte", string fourth = "hello", int fifth = 4) 
     { 
      // But this method ran instead 
      Console.WriteLine("run"); 

     } 


    } 
} 
+0

如果您想運行'optMethod'的第一個聲明,您需要明確指定'third'變量:'new Venusaur()。optMethod(「thirdStr」,fourth:「s」);' –

+0

'我不確定這個問題是否會在主題上考慮。但是,要回答你的問題:使用命名參數是非常不尋常的,儘管它在C#中是允許的。我記得的唯一一個真實世界的例子是XNA和MonoGame(它看起來醜陋而古怪,我認爲它們可以做得更好)。 –

+0

@jsve明確指定第三個變量將不起作用,因爲兩個方法的參數名稱相同,所以編譯器會感到困惑。它會產生「模糊方法調用錯誤」。我已經試過這個代碼:new Venusaur()。optMethod(third:「thirdStr」,fourth:「s」);不太清楚你如何「突出顯示你的代碼」以獲得回覆和答覆。 – Nicholas

回答

3

我找到你的第一個參數完全似是而非的。不管喜不喜歡,參數的名稱都是每個方法語義的一部分,特別是對於將在子類中被覆蓋的抽象類和方法。參數的名稱是一個關鍵信號,告訴用戶該方法的語義方法以及該語義中的每個參數角色。進一步講,理解整個類層次結構中的語義是至關重要的,即參數名稱是一致的,不受每個級別的個別程序員的興趣所影響。

你的第二個參數我覺得完全無法理解。如果你在這裏確實有一個有效的觀點,我建議你重寫一下,以獲得更好的清晰度。

這就是說,我很少在我的方法調用中使用命名參數;對於接受兩個以上相同類型的連續參數的方法而言是例外。在這種情況下,我喜歡將它們命名,這樣我作爲代碼的未來讀者,實際上可以破譯方法的使用,而不必經常懸停以查看智能感。

+0

參數名稱**不是**方法簽名的一部分。根據C#規範(3。6):*方法的簽名由方法的名稱,類型參數的數量以及每個形式參數的類型和種類(值,參考或輸出)組成,按照從左到右的順序考慮。 * –

+0

儘管重載解析將使用參數名稱來查找符合條件的方法。 –

+0

@TheodorosChatzigiannakis:我已經將*簽名*更改爲*語義*,因爲這符合您制定的技術要點,並且更清楚地說明了我的論點的意圖。然而正如Lasse Karlsen所指出的那樣,參數名稱也不能完全排除編譯器對代碼的解釋。 –

7

命名參數是爲了使與COM(及類似技術)的互操作性更容易而添加的另一項技術。

採取method to open a Word document using COM

Document Open(
    [In] ref object FileName, 
    [In, Optional] ref object ConfirmConversions, 
    [In, Optional] ref object ReadOnly, 
    [In, Optional] ref object AddToRecentFiles, 
    [In, Optional] ref object PasswordDocument, 
    [In, Optional] ref object PasswordTemplate, 
    [In, Optional] ref object Revert, 
    [In, Optional] ref object WritePasswordDocument, 
    [In, Optional] ref object WritePasswordTemplate, 
    [In, Optional] ref object Format, 
    [In, Optional] ref object Encoding, 
    [In, Optional] ref object Visible, 
    [In, Optional] ref object OpenAndRepair, 
    [In, Optional] ref object DocumentDirection, 
    [In, Optional] ref object NoEncodingDialog, 
    [In, Optional] ref object XMLTransform 
); 

它具有不低於16的參數,其中15個是可選的。

如果您想指定XMLTransform參數但不關心其他參數,該怎麼辦?

你將不得不指定其餘的位置參數。隨着命名參數調用簡單地變爲:

doc.Open("somefilename.doc", XMLTransform: xxx); 

隨着dynamic和一些其他的東西,它並不意味着是一個很好的解決了很多問題,但是當你有一個嚴重依賴於方法的API有很多很多參數,其中大多數是可選的,命名參數是有意義的。

是的,你可以亂序指定參數。這並不意味着這是一個好主意,也不意味着它解決了人們真正擁有的問題。

1

1)我不明白「信息隱藏」在哪裏;方法簽名就是你要求最終用戶給你的。他顯然需要知道數據類型和名稱,以消除爲什麼參數指向什麼。此外,他仍然不知道你會如何處理你所要求的參數(也許沒有),所以需要隱藏的東西仍然隱藏着。

2)這裏的問題是兩個重載不好的選擇,這兩個重載的區別僅在於參數個數的不同,它與忽略某些參數(由可選參數提供)的能力相結合使您失去區分它們的「好處」 (除非你給出所有參數)

命名參數(一部分)與interop場景動態引入;例如在Office自動化中,在C#3中,您需要添加一堆Type.Missing參數,然後在C#4中,您可以提供您需要的那些參數。

0

關於COM inter-op的觀點是最重要的。

我個人傾向於使用它,如果我想要使用方法簽名中的布爾參數,但沒有明顯的變量可以使用。 例子:

我覺得更易讀

var isSuccessful = myObject.Method(isRecursive: true) 

然後

var isSuccessful = myObject.Method(true); 

最終你可以更詳細的語法

var isRecursive = true; 
var isSuccessful = myObject.Method(isRecursive); 

避免命名參數。

像這樣調用方法的明顯缺點是,如果由於某種原因方法的簽名更改,您的代碼將不再生成。