Mam obiekt, który jest moim stanem pamięci programu, a także kilka innych funkcji roboczych, do których przekazuję obiekt, aby zmodyfikować stan. Przekazywałem to przez odwołanie do funkcji robotniczych. Jednak natrafiłem na następującą funkcję.
byte[] received_s = new byte[2048];
IPEndPoint tmpIpEndPoint = new IPEndPoint(IPAddress.Any, UdpPort_msg);
EndPoint remoteEP = (tmpIpEndPoint);
int sz = soUdp_msg.ReceiveFrom(received_s, ref remoteEP);
To mnie dezorientuje, ponieważ oba received_s
i remoteEP
zwracają rzeczy z funkcji. Dlaczego remoteEP
potrzebujemy ref
i received_s
nie robi?
Jestem też programistą AC, więc mam problem z wyrzuceniem wskaźników z mojej głowy.
Edycja: wygląda na to, że obiekty w C # są wskaźnikami do obiektu pod maską. Więc kiedy przekazujesz obiekt do funkcji, możesz następnie zmodyfikować zawartość obiektu za pomocą wskaźnika, a jedyną rzeczą przekazaną do funkcji jest wskaźnik do obiektu, aby sam obiekt nie był kopiowany. Używasz ref lub out, jeśli chcesz mieć możliwość przełączania się lub tworzenia nowego obiektu w funkcji, który jest podobny do podwójnego wskaźnika.
if (int.TryParse(text, out int value)) { ... use value here ... }
Pomyśl o parametrze innym niż ref jako wskaźniku, a parametrze ref jako o podwójnym wskaźniku. To mi najbardziej pomogło.
Prawie nigdy nie powinieneś przekazywać wartości przez ref. Podejrzewam, że gdyby nie problemy związane z interopem, zespół .Net nigdy nie umieściłby tego w oryginalnej specyfikacji. Sposobem OO rozwiązania większości problemów, które rozwiązują parametry ref, jest:
Dla wielu wartości zwracanych
Dla prymitywów, które zmieniają się w metodzie w wyniku wywołania metody (metoda ma skutki uboczne w parametrach pierwotnych)
źródło
IPAddress.TryParse(string, out IPAddress)
.if (int.TryParse("123", out var theInt) { /* use theInt */ }
mieli.var candidate = int.TrialParse("123"); if (candidate.Parsed) { /* do something with candidate.Value */ }
Jest więcej kodu, ale jest znacznie bardziej spójny z projektem języka C #.Prawdopodobnie możesz napisać całą aplikację C # i nigdy nie przekazywać żadnych obiektów / struktur przez ref.
Miałem profesora, który powiedział mi to:
Zgadzam się z jego radą i przez ponad pięć lat, które minęły od szkoły, nigdy nie potrzebowałem tego poza wywoływaniem Framework lub Windows API.
źródło
SetName(person, "John Doe")
, właściwość name ulegnie zmianie i ta zmiana zostanie odzwierciedlona dla dzwoniącego.Ponieważ otrzymane_s jest tablicą, przekazujesz wskaźnik do tej tablicy. Funkcja manipuluje istniejącymi danymi w miejscu, nie zmieniając podstawowej lokalizacji ani wskaźnika. Słowo kluczowe ref oznacza, że przekazujesz rzeczywisty wskaźnik do lokalizacji i aktualizujesz ten wskaźnik w funkcji zewnętrznej, więc wartość w funkcji zewnętrznej ulegnie zmianie.
Np. Tablica bajtów jest wskaźnikiem do tej samej pamięci przed i po, pamięć została właśnie zaktualizowana.
Odwołanie do punktu końcowego w rzeczywistości aktualizuje wskaźnik do punktu końcowego w funkcji zewnętrznej do nowego wystąpienia wygenerowanego wewnątrz funkcji.
źródło
Pomyśl o odnośniku jako o tym, że przekazujesz wskaźnik przez odniesienie. Nieużywanie ref oznacza, że przekazujesz wskaźnik według wartości.
Jeszcze lepiej, zignoruj to, co właśnie powiedziałem (prawdopodobnie wprowadza w błąd, szczególnie w przypadku typów wartości) i przeczytaj tę stronę MSDN .
źródło
rozumiem, że wszystkie obiekty wywodzące się z klasy Object są przekazywane jako wskaźniki, podczas gdy typy zwykłe (int, struct) nie są przekazywane jako wskaźniki i wymagają ref. Nie jestem pewien co do ciągu (czy ostatecznie pochodzi z klasy Object?)
źródło
Chociaż ogólnie zgadzam się z odpowiedzią Jona Skeeta i niektórymi innymi odpowiedziami, istnieje przypadek użycia
ref
, który służy do zaostrzenia optymalizacji wydajności. Podczas profilowania wydajności zaobserwowano, że ustawienie wartości zwracanej metody ma niewielki wpływ na wydajność, podczas gdy użycieref
jako argumentu, w którym wartość zwracana jest umieszczana w tym parametrze, powoduje usunięcie tego niewielkiego wąskiego gardła.Jest to naprawdę przydatne tylko wtedy, gdy wysiłki optymalizacyjne są podejmowane na skrajnych poziomach, poświęcając czytelność, a być może testowalność i łatwość konserwacji, aby zaoszczędzić milisekundy lub może ułamek milisekund.
źródło
Najpierw reguła punktu zerowego, prymitywy są przekazywane przez wartość (stos), a nie-prymitywne przez odwołanie (sterta) w kontekście zaangażowanych TYPÓW.
Uwzględnione parametry są domyślnie przekazywane przez wartość. Dobry post, który szczegółowo wyjaśnia wszystko. http://yoda.arachsys.com/csharp/parameters.html
Możemy powiedzieć (z ostrzeżeniem) Typy niebędące prymitywami to nic innego jak wskaźniki A kiedy mijamy je przez ref możemy powiedzieć, że przechodzimy przez Double Pointer
źródło