6

在C#程序中,我製作了一個從列表中刪除對象的方法。用戶輸入要刪除的項目的索引,然後要求用戶確認刪除,並且如果用戶確認該項目從列表中移除,否則該列表保持不變。
我不確定將參數傳遞給方法的最佳方式。我試圖通過引用傳遞列表(作爲out參數):在C#中,我應該通過值傳遞一個參數並返回相同的變量,或通過引用?

static void DeleteCustomer(out List<Customer> customers) 
{ 
    // ...display list of objects for user to choose from... 
    int deleteId = ReadInt("Enter ID of customer to delete: "); 
    Console.Write("Are you sure you want to delete this customer?"); 
    if (Console.ReadLine().ToLower() == "y") 
    { 
     customers.RemoveAt(deleteId); 
    } 
} 

,因爲我得到了錯誤使用未分配的局部變量的「客戶」的輸出參數的客戶上面的代碼不起作用'必須在控制離開當前方法之前分配。我想我可以按值傳遞的列表,並返回相同的列表,像這樣:

static List<Customer> DeleteCustomer(List<Customer> customers) 
{ 
    int deleteId = ReadInt("Enter ID of customer to delete: "); 
    Console.Write("Are you sure you want to delete this customer?"); 
    if (Console.ReadLine().ToLower() == "y") 
    { 
     customers.RemoveAt(deleteId); 
    } 
    return customers; 
} 

// ...which would be called from another method with: 
List<Customer> customers = DeleteCustomer(customers); 

,但這似乎並不有效,因爲相同的變量是按值傳遞之後返回。

在這種情況下傳遞參數的最有效方法是什麼?

+1

列表自動通過引用傳遞,因此不需要返回它。調用方法將看到在對傳遞列表的引用中反映的更改。 – user469104 2014-12-02 18:27:07

+2

請參見:[參數在C#中傳遞 - Jon Skeet](http://www.yoda.arachsys.com/csharp/parameters.html)。也可以嘗試第二種方法,但不返回列表,您將看到它已被更改。這是因爲引用類型的地址是按值傳遞的。 **但重要的是**,你不應該擔心效率*現在*,考慮編寫代碼來更清楚地表達意圖,並且稍後纔會尋求提高性能。 – Habib 2014-12-02 18:29:01

+0

第二種方法可以有一個返回類型'void'。 – 2014-12-02 18:31:07

回答

4

List像所有引用類型,是作爲參考的對象,而不是它的一個副本傳遞。

注意,這是說,它是由引用傳遞很大的不同,因爲這將意味着該參數的賦值傳播給調用者,它不

它確實意味着修改的對象(例如由RemoveAt執行的對象)將自動傳播給調用者。

因此,只是通過它;不需要返回值或out/ref參數。

你將很少使用out/ref對於引用類型,並用於值類型時,性能差異會如此之小,回訪,你不應該擔心它,除非你具有一定輪廓並提出確保那那裏出現問題。使用最具慣用意義的東西。

+2

'像所有引用類型的列表一樣,是作爲引用傳遞給對象的,而不是它的副本。這意味着修改會自動傳播給調用者。這是不正確的。您不能將'null'或新實例分配給您的傳遞對象。引用類型的地址是按值傳遞的。 – Habib 2014-12-02 18:33:08

+1

@Habib完全同意。它通過*作爲參考;不*通過*參考。通過引用傳遞引用是不同的。你有一個更有意義的措辭嗎?有時候我真的希望我們有指針,它更容易解釋......我也編輯了(當你打字時?)以澄清傳播陳述。 – BradleyDotNET 2014-12-02 18:34:02

+3

它是一個棘手的聲明,我更傾向於說,除非使用ref/out關鍵字,否則C#中的任何內容都不會被引用傳遞。對於引用類型,引用/地址作爲值傳遞。 – Habib 2014-12-02 18:36:18

2

在C#中,參數是按值傳遞的。這意味着,當您將參數傳遞給方法時,會傳遞該參數的副本。 C#根據值(如int)和引用(像任何類)有類型。 C#包含一個棧(當推送所有變量時)和一個堆。值類型的值直接在堆棧中推送,而引用類型的引用在堆棧中推入,並且引用的值在堆中推送。
當你傳遞一個引用類型(如List)時,它會複製引用,但是這個複製指向同一個對象到列表中。因此,除非您更改引用(帶有assigmet),否則任何更改都會直接影響對象,但這不是您的情況。

這可能是你的代碼:

static void DeleteCustomer<T>(List<T> customers) 
    { 
     Console.WriteLine("Enter ID of customer to delete: "); 
     int deleteId; 
     if (int.TryParse(Console.ReadLine(), out deleteId)) // if the input is an int 
     { 
      Console.Write("Are you sure you want to delete this customer?"); 
      if (Console.ReadLine().ToLower() == "y") 
      { 
       customers.RemoveAt(deleteId); 
      } 
     } 
     else 
     { 
      Console.WriteLine("This is not valid Id"); 
     } 
    } 

如果您想了解裁判的關鍵字out我可以幫你,但是這個例子不是neccesary。

相關問題