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

+2

См. [Параметр, проходящий в C# - Джон Скит] (http://www.yoda.arachsys.com/csharp/parameters.html). Также попробуйте второй метод, не возвращая список, вы увидите, что он был изменен. Это связано с тем, что адрес ссылочного типа передается по значению. ** Но важно **, вы не должны беспокоиться об эффективности * сейчас *, подумайте над тем, как писать код, который более четко передает намерение и только позже будет выглядеть для улучшения производительности. – Habib

+0

Второй метод может иметь тип возврата 'void'. –

ответ

4

List как и все ссылочные типы, передается как ссылка на объект, а не его копию.

Обратите внимание, что это очень отличается от того, что передается с помощью ссылки, так как это будет означать, назначение параметра распространяется к абоненту, который он не

Это делает означает, что изменения в объект (например, выполняемый RemoveAt) будет автоматически распространяться на вызывающего абонента.

Таким образом, просто передайте его; нет необходимости в возвращаемом значении или out/ref параметров.

Вы очень редко используете out/ref для ссылочных типов, а также при использовании для типов значений, разница в производительности будет настолько мала по сравнению с возвращением, что вы не должны беспокоиться об этом, если вы не профилированных и сделали уверен что проблема там возникает. Используйте то, что делает самый идиоматический смысл.

+2

«Список, как и все ссылочные типы, передается как ссылка на объект, а не его копия. Это означает, что изменения будут автоматически распространяться на вызывающего абонента. Это неверно. Вы не можете назначить «null» или новый экземпляр для вашего переданного объекта. Адрес ссылочного типа передается по значению. – Habib

+1

@ Хабиб Полностью согласован. Он передается * как * ссылка; нет * by * справка. Передача ссылки по ссылке отличается. У вас есть формулировка, которая имеет больше смысла для вас? Иногда мне действительно хотелось, чтобы у нас были указатели, это намного проще объяснить ... Я также редактировал (пока вы печатали?), Чтобы прояснить утверждение распространения. – BradleyDotNET

+3

Его сложное утверждение, я более склонен сказать, что ничто в C# не передается по ссылке, если не используется ключевое слово ref/out. Для ссылочных типов ссылка/адрес передается как значение. – Habib

2

В C# параметр передается по значению. Это означает, что при передаче параметра методу передается копия параметра. C# имеют типы по значению (например, int) и по ссылке (как и любой класс). C# содержит стек (при нажатии всех переменных) и кучу. Значение типов значений нажимается непосредственно в этом стеке, а ссылка ссылочного типа нажимает на стек, а ссылочное значение вставляется в кучу.
Когда вы передаете ссылочный тип (например, список), он создает копию ссылки, но эта копия указывает на тот же объект в списке. Поэтому любое изменение влияет непосредственно на объект, если вы не измените ссылку (с помощью 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"); 
     } 
    } 

Если вы хотите знать о исх установлена ​​его ключевое слово я могу помочь вам тоже, но для этого примера не neccesary.

Смежные вопросы