6

W programie C# stworzyłem metodę, która usuwa obiekt z listy. Użytkownik wprowadza indeks elementu, który ma zostać usunięty, następnie użytkownik jest proszony o potwierdzenie usunięcia, a pozycja zostaje usunięta z listy, jeśli użytkownik ją potwierdzi, w przeciwnym razie lista pozostanie taka sama.
Nie jestem pewien co do najlepszego sposobu przekazywania argumentów do metody. Próbowałem przechodzącą listy przez odniesienie (jako parametr out):W języku C# należy przekazać parametr według wartości i zwrócić tę samą zmienną lub przekazać przez odniesienie?

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); 
    } 
} 

Powyższy kod nie działa jak dostaję błędy wykorzystania nieprzydzielonej zmiennej lokalnej i Parametr out „klienci 'klientów "musi być przypisany, zanim kontrola opuści bieżącą metodę. Myślałam mogłem przejść przez listę wartości i powrót tej samej listy, jak to:

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); 

ale to nie wydaje się skuteczny, jak sama zmienna jest przekazywane przez wartość, a następnie powrócił.

Jaki jest najbardziej skuteczny sposób przekazywania argumentów w tym przypadku?

+1

Lista jest przekazywana automatycznie przez odniesienie, więc nie trzeba jej zwracać. Metoda wywołująca zobaczy zmianę odzwierciedloną w odniesieniu do przekazanej listy. – user469104

+2

Zobacz: [Parameter passing in C# - autor: Jon Skeet] (http://www.yoda.arachsys.com/csharp/parameters.html). Spróbuj także drugiej metody, bez zwracania listy, zobaczysz, że została zmieniona. Dzieje się tak dlatego, że adres typu referencyjnego jest przekazywany według wartości. ** Ale co ważniejsze **, nie powinieneś martwić się wydajnością * teraz *, rozważ pisanie kodu, który wyraźniej oddaje intencję, a dopiero później poszukaj poprawy wydajności. – Habib

+0

Druga metoda może mieć typ zwrotu "void". –

Odpowiedz

4

List, podobnie jak wszystkie typy odniesienia, jest przekazywane do obiektu jako odniesienie, a nie do jego kopii.

Należy zauważyć, że jest to bardzo różni się od mówiąc, jest ona przekazywana przez odniesienia, jak to oznaczałoby przypisanie parametru rozchodzi się do abonenta, który nie

to nie oznacza, że ​​modyfikacje obiekt (taki jak wykonywany przez RemoveAt) będzie automatycznie propagował do osoby dzwoniącej.

Tak, po prostu przekazać; nie ma potrzeby zwracania wartości ani parametrów out/ref.

Będziesz bardzo rzadko korzystają out/ref dla typów referencyjnych, a użyte dla typów wartości, różnica wydajności będzie tak mała w porównaniu powrocie, że nie należy martwić się o to, chyba że posiadają wyprofilowane i wykonane pewny że problem występuje tam. Użyj tego, co czyni najbardziej idiomatyczny sens.

+2

'Lista jak wszystkie typy odniesienia, jest przekazywana jako odniesienie do obiektu, a nie jego kopia. Oznacza to, że modyfikacje będą automatycznie propagowane do osoby dzwoniącej. To nie jest poprawne. Nie możesz przypisać 'null' lub nowej instancji do przekazanego obiektu. Adres typu referencyjnego jest przekazywany według wartości. – Habib

+1

@Habib Całkowicie uzgodniony. Jest przekazywana * jako * referencja; not * by * reference. Przekazywanie odniesienia przez odniesienie jest inne. Czy masz sformułowanie, które ma dla ciebie więcej sensu? Czasami naprawdę żałuję, że nie mamy wskazówek, o wiele łatwiej jest to wyjaśnić ... Ja również zredagowałem (podczas pisania), aby wyjaśnić oświadczenie o propagacji. – BradleyDotNET

+3

Jest to trudne stwierdzenie, jestem bardziej skłonny powiedzieć, że nic w C# jest przekazywane przez odniesienie, chyba że użyto słowa kluczowego ref/out. W przypadku typów odniesienia odniesienie/adres jest przekazywany jako wartość. – Habib

2

W języku C# parametr jest przekazywany według wartości. Oznacza to, że po przekazaniu parametru do metody przekazuje się kopię parametru. C# mają typy według wartości (np. Int) i odniesienia (jak każda klasa). C# zawiera stos (gdy wypycha wszystkie varaibles) i stertę. Wartość typów wartości pcha bezpośrednio w tym stosie, podczas gdy referencja typu referencyjnego jest pchana w stos, a przywoływana wartość jest pchana w stertę.
Po przekazaniu typu odniesienia (takiego jak lista) tworzy kopię odwołania, ale ten punkt kopiowania do tego samego obiektu na liście. Dlatego każda zmiana wpływa bezpośrednio na obiekt, chyba że zmienisz odniesienie (z assigmet), ale to nie jest twój przypadek.

ten mógł przez kodzie:

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"); 
     } 
    } 

Jeśli chcesz wiedzieć o sygn się na zewnątrz słowa kluczowego mogę pomóc też, ale w tym przykładzie nie jest neccesary.

Powiązane problemy