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。

相关问题