Podaj a, ref
jeśli chcesz zmienić obiekt:
TestRef t = new TestRef();
t.Something = "Foo";
DoSomething(ref t);
void DoSomething(ref TestRef t)
{
t = new TestRef();
t.Something = "Not just a changed t, but a completely different TestRef object";
}
Po wywołaniu DoSomething t
nie odnosi się do oryginału new TestRef
, ale odnosi się do zupełnie innego obiektu.
Może to być również przydatne, jeśli chcesz zmienić wartość niezmiennego obiektu, np string
. Nie można zmienić wartości string
raz utworzonej. Ale używając a ref
, możesz utworzyć funkcję, która zmienia łańcuch na inną, która ma inną wartość.
Edycja: jak wspomnieli inni ludzie. Nie jest dobrym pomysłem używanie, ref
chyba że jest to potrzebne. Użycie ref
daje tej metodzie swobodę zmiany argumentu na coś innego, wywołujące metodę będą musiały zostać zakodowane, aby upewnić się, że poradzą sobie z tą możliwością.
Ponadto, gdy typ parametru jest obiektem, wówczas zmienne obiektu zawsze działają jako odniesienia do obiektu. Oznacza to, że po użyciu ref
słowa kluczowego masz odniesienie do odwołania. Umożliwia to wykonywanie czynności opisanych w powyższym przykładzie. Ale jeśli typ parametru jest pierwotną wartością (np. int
), To jeśli parametr ten jest przypisany do metody, wartość przekazanego argumentu zostanie zmieniona po zwróceniu metody:
int x = 1;
Change(ref x);
Debug.Assert(x == 5);
WillNotChange(x);
Debug.Assert(x == 5); // Note: x doesn't become 10
void Change(ref int x)
{
x = 5;
}
void WillNotChange(int x)
{
x = 10;
}
ref
na stronie połączenia… gdzie jeszcze chcesz, żeby to było wyróżnione? Semantyka jest również dość jasna, ale należy ją wyrazić ostrożnie (zamiast „obiektów przekazuje się przez odniesienie”, co jest powszechnym nadmiernym uproszczeniem).W .NET, gdy przekazujesz dowolny parametr do metody, tworzona jest kopia. W typach wartości oznacza, że wszelkie modyfikacje wartości są w zakresie metody i są tracone po wyjściu z metody.
Przy przekazywaniu typu odniesienia tworzona jest również kopia, ale jest to kopia odniesienia, tj. Teraz masz DWA odniesienia w pamięci do tego samego obiektu. Jeśli więc użyjesz odwołania do zmodyfikowania obiektu, zostanie on zmodyfikowany. Ale jeśli zmodyfikujesz sam odnośnik - musimy pamiętać, że jest to kopia - wtedy wszelkie zmiany zostaną utracone po wyjściu z metody.
Jak powiedziano wcześniej, przypisanie jest modyfikacją odwołania, a zatem zostaje utracone:
Powyższe metody nie modyfikują oryginalnego obiektu.
Mała modyfikacja twojego przykładu
źródło
Ponieważ TestRef jest klasą (które są obiektami referencyjnymi), możesz zmienić zawartość wewnątrz t bez przekazywania jej jako referencji. Jeśli jednak podasz t jako odwołanie, TestRef może zmienić to, do czego odnosi się pierwotne t. tzn. wskaż inny obiekt.
źródło
Dzięki
ref
niemu możesz napisać:I t zostanie zmienione po zakończeniu metody.
źródło
Pomyśl o zmiennych (np.
foo
) Typów referencyjnych (np.List<T>
), Które zawierają identyfikatory obiektów w postaci „Obiekt # 24601”. Załóżmy, że instrukcjafoo = new List<int> {1,5,7,9};
powodujefoo
przechowywanie „Object # 24601” (lista z czterema elementami). Następnie wywołaniefoo.Length
zapyta Obiekt # 24601 o jego długość i odpowie 4, więcfoo.Length
będzie równa 4.Jeśli
foo
zostanie przekazany do metody bez użyciaref
, metoda ta może wprowadzić zmiany w obiekcie nr 24601. W wyniku takich zmianfoo.Length
może już nie być równy 4. Jednak sama metoda nie będzie mogła się zmienićfoo
, co nadal będzie zawierać „Obiekt # 24601”.Przekazanie
foo
jakoref
parametru pozwoli wywoływanej metodzie wprowadzić zmiany nie tylko do obiektu # 24601, ale także dofoo
samego siebie. Metoda może utworzyć nowy obiekt # 8675309 i zapisać w nim odwołaniefoo
. Jeśli tak się stanie,foo
nie będzie już zawierał „Object # 24601”, ale „Object # 8675309”.W praktyce zmienne typu odniesienia nie zawierają ciągów znaków „Obiekt # 8675309”; nawet nie przechowują niczego, co można znacząco przekształcić w liczbę. Mimo że każda zmienna typu referencyjnego będzie zawierać pewien wzorzec bitowy, nie ma stałej zależności między wzorami bitowymi przechowywanymi w takich zmiennych a obiektami, które identyfikują. W żaden sposób kod nie może wyodrębnić informacji z obiektu lub odwołania do niego, a następnie ustalić, czy inne odwołanie zidentyfikowało ten sam obiekt, chyba że kod przechowywał lub wiedział o odwołaniu, które zidentyfikowało obiekt oryginalny.
źródło
To jest jak przekazanie wskaźnika do wskaźnika w C. W .NET pozwoli ci to zmienić to, o czym mówi oryginalny T, choć osobiście uważam, że jeśli robisz to w .NET, prawdopodobnie masz problem z projektem!
źródło
Używając
ref
słowa kluczowego z typami referencji, skutecznie przekazujesz referencję do referencji. Na wiele sposobów jest to to samo, co użycieout
słowa kluczowego, ale z tą niewielką różnicą, że nie ma gwarancji, że metoda faktycznie przypisze cokolwiek doref
parametru ed.źródło
ref
naśladuje (lub zachowuje się) jako obszar globalny tylko dla dwóch zakresów:źródło
Jeśli jednak podajesz wartość, rzeczy wyglądają inaczej. Możesz wymusić przekazanie wartości przez referencję. Dzięki temu możesz na przykład przekazać liczbę całkowitą do metody i pozwolić metodzie zmodyfikować liczbę całkowitą w Twoim imieniu.
źródło
Ref oznacza, czy funkcja może dostać się w ręce samego obiektu, czy tylko jego wartości.
Przekazywanie przez odniesienie nie jest związane z językiem; jest to strategia wiązania parametrów obok parametru pass-by-value, pass by name, pass by need itp ...
Krótka informacja: nazwa klasy
TestRef
jest w tym kontekście okropnie złym wyborem;).źródło