Czy tablice lub listy są przekazywane domyślnie przez odwołanie w języku C #?

86

Czy oni? Czy, aby przyspieszyć mój program, powinienem przekazać je przez odniesienie?

Jorge Branco
źródło
35
Aby przyspieszyć program, powinieneś (1) wyznaczyć sensowne cele, (2) sprawdzić, czy osiągnąłeś swoje cele, (3) jeśli nie, użyj narzędzia do profilowania, aby znaleźć najwolniejszą rzecz oraz (4) ) zoptymalizować najwolniejszą rzecz.
Eric Lippert
1
Zobacz także stackoverflow.com/q/4311226/344822
prabhakaran
3
@EricLippert Twój komentarz odpowiada na prawdziwe pytanie OP o wiele lepiej niż jakiekolwiek z opublikowanych odpowiedzi. Wszyscy byli tak rozproszeni technicznymi aspektami „przekazywania referencji według wartości”, że całkowicie przeoczyli prawdziwe pytanie o optymalizację wydajności. Niestety OP raczej słabo przekazał swoje potrzeby, a pozostałe odpowiedzi przynajmniej pomogą Google.
Dan Bechard
„inne odpowiedzi przynajmniej pomogą tłumowi Google” - tak! :)
miki

Odpowiedzi:

210

Odniesienia jest przekazywane przez wartość .

Tablice w .NET są obiektami na stercie, więc masz odniesienie. To odwołanie jest przekazywane przez wartość, co oznacza, że wywołujący zobaczy zmiany w zawartości tablicy, ale ponowne przypisanie tablicy nie:

void Foo(int[] data) {
    data[0] = 1; // caller sees this
}
void Bar(int[] data) {
    data = new int[20]; // but not this
}

Jeśli dodasz refmodyfikator, odwołanie jest przekazywane przez odniesienie - a wywołujący zobaczy zmianę powyżej.

Marc Gravell
źródło
28
Odpowiedź jest prawidłowa, ale nienawidzę ludzi, którzy twierdzą, że „referencja jest przekazywana przez wartość”. To myli sprawę. Tak, referencje (adresy pamięci) są przekazywane według wartości, ale nie o to chodziło.
WernerVA
9
@WernerVA Interesuje mnie, jak myślisz, że wyrazisz to inaczej, co pozostaje poprawne i jednoznaczne
Marc Gravell
2
Nie wyraziłbym tego inaczej, tylko może trochę więcej szczegółów.
WernerVA
To nie odpowiada na część pytania dotyczącą szybkości. Prawdopodobnie jest dla ciebie oczywiste, że optymalizacja kopii referencyjnej będzie całkowicie nieistotna w porównaniu z setkami innych znacznie droższych operacji, które mają miejsce, ale OP zadał to konkretnie.
Dan Bechard
7
@Dan, część dotycząca szybkości jest nieodłącznie związana z „jeśli tablica jest przekazywana przez wartość - co oznacza kopię zawartości tablicy - oznacza to alokację i kopię całej pamięci”. Ponieważ jest to odniesienie, które zostało przekazane, nie ma pytania o wykonanie, na które można by odpowiedzieć - ta część pytania staje się dyskusyjna i odpowiedź jest automatyczna. Z wyjątkiem tego, że teraz odpowiedź jest również tutaj wyraźnie w komentarzach ...
Marc Gravell
10

Są przekazywane przez wartość (podobnie jak wszystkie parametry, które nie są ani ref ani out), ale wartość jest odwołaniem do obiektu, więc są skutecznie przekazywane przez odniesienie.

cokół
źródło
0

Tak, są one domyślnie przekazywane przez odwołanie w języku C #. Wszystkie obiekty w C # są, z wyjątkiem typów wartości. Aby być trochę bardziej precyzyjnym, są one przekazywane „przez odniesienie według wartości”; to znaczy, wartość zmiennej, którą widzisz w metodach, jest odniesieniem do przekazanego oryginalnego obiektu. To jest mały punkt semantyczny, ale czasami może być ważny.

Paul Sonier
źródło
9
Odwołanie jest przekazywane przez wartość; co bardzo różni się od „są przekazywane przez odniesienie”.
Marc Gravell
1
To jest dokładne przeciwieństwo prawdy. Cytując ten post od Johna Skeeta : „Domyślnie wszystkie parametry są przekazywane przez wartość w C #. Parametry są przekazywane tylko przez odwołanie, jeśli jawnie dołączysz modyfikator out lub ref. Należy jednak pamiętać, że gdy typ parametru jest typem referencyjnym, przekazujesz referencję, a nie rzeczywisty obiekt ”. To tylko odniesienie (adres pamięci) jest przekazywane przez wartość.
alexlomba87