Przekazywanie parametrów mimo wszechobecności w każdej nawet najprostrzej aplikacji jest często pomijanym elementem w czasie nauki języka. Jest to na tyle prosta i naturalna czynność, że nie każdy zastanawia się jak to na prawdę funkcjonuje. Często słyszy się powszechnie, że: typy wartościowe przekazywane są przez wartość a obiekty przez referencję. Większości tak informacja wystarcza i nie zastanawiają się czy to w ogóle prawda i o co w tym tak na prawdę chodzi. Warto jednak przyjrzeć się temu tematowi choćby z tego powodu, że na rozmowach czy testach kwalifikacyjnych jest to powtarzający się element przy analizie kodu źródłowego. Zatem taka wiedza może okazać się niezbędna o ile zależy wam na dostaniu pracy o którą się ubiegamy.
W języku C# możemy przekazywać zmienne na dwa sposoby poprzez wartość i referencję. Przez wartość przekazujemy parametry podając jedynie ich nazwę jeżeli jednak chcemy aby funkcja miała możliwość dokonywania zmian na przekazywanych parametrach musimy przekazać je przez referencję wykorzystując do tego słowo kluczowe ref lub out. Różnica między tymi słówkami zostanie wyjaśniona w dalszej części.
Przekazywanie parametrów typu wartościowego
Typy wartościowe są najprostszymi dostępnymi typami, przechowują one dane bezpośrednio w przeciwieństwie do typów referencyjnych. Przekazywanie zmiennych typu wartościowego do metody jest równoznaczne z przekazaniem kopi tej zmiennej do metody. Oznacza to tyle, że w metodzie do której przekazaliśmy zmienne posługujemy się kopiami przekazanych zmiennych i zmiany dokonywane na nich nie mają wpływu na zmiany zmiennych które do metody przekazaliśmy.
[csharp]class PassingValByVal
{
static void SquareIt(int x)
{
x *= x;
Console.WriteLine("The value inside the method: {0}", x);
}
public static void Main()
{
int myInt = 5;
Console.WriteLine("The value before calling the method: {0}",
myInt);
SquareIt(myInt); // Passing myInt by value.
Console.WriteLine("The value after calling the method: {0}",
myInt);
}
} [/csharp]
Wynikiem powyższej aplikacji będzie:
The value before calling the method: 5 The value inside the method: 25 The value after calling the method: 5
Przekazując zmienną myInt do metody SquereIt kopiujemy jej zawartość do parametru x. Efektem czego wszystkie zmiany dokonywane są na kopi zmiennej myInt i nie mają żadnego wpływu na tą zmienną. Dlatego zmienna myInt przed jak i po wywołaniu metody SquareIt nie zmieniła swojej wartości.
Jeżeli chcemy dać możliwość metodzie bezpośredniego operowania na zmiennych przekazywanych do niej powinniśmy wykorzystać słowo kluczowe ref lub out.:
[csharp]class PassingValByRef
{
static void SquareIt(ref int x)
{
x *= x;
Console.WriteLine("The value inside the method: {0}", x);
}
public static void Main()
{
int myInt = 5;
Console.WriteLine("The value before calling the method: {0}",
myInt);
SquareIt(ref myInt); // Passing myInt by reference.
Console.WriteLine("The value after calling the method: {0}",
myInt);
}
}[/csharp]
Wynikiem powyższej aplikacji będzie:
The value before calling the method: 5 The value inside the method: 25 The value after calling the method: 25
Jak widzimy po wywołaniu metody SquareIt wartość zmiennej myInt uległa zmianie i uzyskaliśmy efekt o jaki nam chodziło podnieśliśmy do kwadratu zmienną którą przekazaliśmy do metody.
Przekazywanie parametrów typu referencyjnego
Typy referencyjne przechowują adres w pamięci określający gdzie obiekt się znajduje. Warto jednak pamiętać, że sama referencja zawierająca adres obiektu jest typem wartościowym którego wielkość zależy od platformy na jaką aplikacja została utworzona (system 32 lub 64 bitowy). Zatem przekazując zmienną typu referencyjnego przekazujemy ją również przez wartość z tą różnicą, że cały czas jest to wskaźnik na miejsce w pamięci dzięki czemu w metodzie możemy modyfikować obiekt na który przekazana referencja wskazuję. Jednak mimo możliwości zmian w obiekcie nie możemy dokonać zmian na samej referencji gdyż jest to jej kopia.
[csharp]class PassingRefByVal
{
static void Change(StringBuilder sb)
{
sb = new StringBuilder();
sb.AppendLine("Append inside method.");
}
public static void Main()
{
StringBuilder builder = null;
Change(builder);
builder.AppendLine("Append after calling method."); //Exception
Console.WriteLine(builder.ToString());
}
} [/csharp]
Powyższy kod po wykonaniu wyrzuci nam wyjątek NullReferenceException gdyż po wywołaniu metody Change zmienna builder nadal ma wartość null. Dzieje się tak ponieważ do metody przekazaliśmy kopię referencji wskazującej na obiekt klasy StringBuilder. Fakt operowania kopią referencji sprawił, że utworzony obiekt był przypisany do kopi referencji, a nie do zmiennej builder.
Aby móc dokonywać zmian nie tylko na obiekcie ale również na jego referencji musimy dodać słowo kluczowe ref lub out.
[csharp]class PassingRefByRef
{
static void Change(ref StringBuilder sb)
{
sb = new StringBuilder();
sb.AppendLine("Append inside method.");
}
public static void Main()
{
StringBuilder builder = null;
Change(ref builder);
builder.AppendLine("Append after calling method.");
Console.WriteLine(builder.ToString());
}
} [/csharp]
Wynikiem powyższego kodu będzie:
Append inside method. Append after calling method.
Dzięki użyciu słówka ref mogliśmy utworzyć obiekt wewnątrz metody i dokonać na nim zmian.
Więcej o ref i out
W prezentowanych przykładach używaliśmy jedynie słówka ref przy przekazywaniu parametrów przez referencją. Jak wspominałem wcześniej istnieje również możliwość użycia słowa kluczowego out które również umożliwia przekazanie parametru przez referencję. Jednak jest pewna różnica w zastosowaniu tych słów kluczowych. Różnica ta polega na tym, że w metodzie w której przekazujemy parametry ze out musimy zainicjować zmienną którą przekazujemy z tym słowem kluczowym. Ze słówkiem ref sytuacja jest taka, że przed przekazaniem zmiennej do funkcji musimy zmienną najpierw zainicjować.
Musimy również pamiętać, że do metod używających słów kluczowych ref lub out, czyli przekazując zmienne przez referencję nie możemy przekazać właściwości klasy jak również indekserów w niej zdefiniowanych.
Opisywane słowa kluczowe umożliwiają nam również przeciążanie metod dzięki czemu taki zapis jest poprawny:
[csharp]class MyClass
{
public void MyMethod(int i) {i = 10;}
public void MyMethod(out int i) {i = 10;}
}[/csharp]
Słowa kluczowe ref i out możemy użyć zamiennie jednak nie możemy ich użyć razem, dlatego poniższy kod jest niepoprawny:
[csharp]class MyClass
{
public void MyMethod(out int i) {i = 10;}
public void MyMethod(ref int i) {i = 10;}
}[/csharp]
Podsumowanie
Wracając do stwierdzenia przedstawionego na początku tego postu: typy wartościowe przekazywane są przez wartość a obiekty przez referencję nie trudno stwierdzić że jest to przesadne uogólnienie które nie jest prawdą. Typy wartościowe jak i typy referencyjne przekazujemy przez wartość mimo faktu że dzięki referencji możemy modyfikować obiekty na które ona wskazuje. Aby przekazać zmienne przez referencję musimy dodatkowo użyć jednego ze słów kluczowych ref i out które też mają swoją specyfikę i podlegają pewnym ograniczeniom o czym należy pamiętać. Kończąc chciałbym życzyć wszystkim udanych rozmów kwalifikacyjnych.
Wpis powstał na podstawie: Passing Parameters, Passing Arrays Using ref and out
Link exchange is certainly not else however it is actually only placing the other person’s website link on your page at suitable place and also other person will even do same in support of
you.
10 мм глисты у котенка http://newscenemedia.xyz/index.php?id=2362 гельминты гострики фото
It is actually a nice and helpful piece of information. I’m satisfied that you just shared this useful info with us.
Please stay us informed like this. Thank you for sharing.
как часто нужно делать анализ на выявления вируса папилломы человека http://herambitions.xyz/index.php?viewurl=6454 дезинфекция яйца глистов
квашеная гепатит можно есть http://krazygoat.xyz/index.php?topic=12211 глисты чихуа хуа
при описторхозе выпадают волосы http://akkaka.us/index.php?link=21017 физиотерапевтическое лечение артроза внчс
где можно сдать соскоб на глистов http://balbebee.xyz/index.php?viewpage=8434 первые симптомы герпеса на члене фото
слабы боли в суставах http://onlinekase.xyz/index.php?id=18542 чем наркологи лечат алкоголизм
Hi! I’m at work browsing your blog from my new iphone 3gs!
Just wanted to say I love reading your blog and look forward to all your posts!
Keep up the great work!
как делать гимнастику для остеохондроза шейного отдела http://vihelp.ru/index.php?page-id=4550 пирантел содержат такие препараты
елена малышева об остеохондрозе видео http://daveandsonia.xyz/index.php?viewurl=893 фото вибромассаж простаты самому
Hi, i believe that we saw you visited my web site thus i came
to go back the want?.I’m trying to in locating things to enhance my website!I suppose
its ok to work with some of your ideas!!
ткач леонида михайловича кодировка от алкоголизма http://planete-dys.xyz/index.php?id=10327 ворма расписки при дтп
давление после того как бросил пить http://iapnevada.xyz/index.php?topic=7938 гепатит в симптомы и лечение у мужчин фото
соблюдение диеты при гепатите http://floorplanhouses.xyz/index.php?viewurl=2939 как замаскировать грибок на стене
ревматоидный артрит после родов лечение http://chavezfencing.xyz/index.php?viewpage=8144 увеличенные паразиты
длительная диарея боль в суставах http://centr-vt.ru/index.php?page-id=6876 детский алкоголизм как начинается и чем заканчивается
дают ли больничный при артрозе тазобедренных суставов http://ichriblechflous.xyz/index.php?topic=3168 вирус папилломы человека 33 52 58 лечение
чем отличаются ревматизм от ревматоидного полиартрита http://over50sfinalexpenses.xyz/index.php?id=10899 таблетки от герпеса на губах 3 штуки
Great post.
After study a couple of of the blog posts in your web site now, and I really like your manner of blogging. I bookmarked it to my bookmark web site checklist and will probably be checking again soon. Pls try my web site as nicely and let me know what you think.
Awesome post.
храп ребенка в 1 год 6 месяцев http://bebbox.us/index.php?link=8515 элос омоложение отзывы украина
фото воспаленной бородавки http://agilane.us/index.php?link=23993 что такое лямблии и как их лечить у детей фото
как лечить генитальный герпес и мужчине и женщине http://naturesgold.xyz/index.php?id=10971 как анонимно можно заставить мужа бросить пить
форум операция варикоза вен на ногах http://oombo.xyz/index.php?id=1115 упражнения головы от остеохондроза шейного