Jaki problem chcemy rozwiązać?
Załóżmy, że mamy prostą aplikację konsolową. W metodzie Main mamy najpierw inicjalizację zmiennej typu int o nazwie myNumber, a następnie wywołujemy 3 razy metodę IncrementValue, która powinna za każdym razem zwiększyć wartość naszej zmiennej o 1. Czyli taki kod, może wyglądać w ten sposób:
using System;
namespace Demo
{
class Program
{
static void Main()
{
int myNumber = 0;
IncrementValue(myNumber);
IncrementValue(myNumber);
IncrementValue(myNumber);
Console.WriteLine(myNumber);//0
}
public static void IncrementValue(int value)
{
value++;
}
}
}
Niestety nasza zmienna nie została zwiększona i nadal ma wartość 0. Dlaczego tak się stało? Zmienna myNumber jest typu int, a int jest typem prostym (typem wartościowym) i przez to, do metody IncrementValue została przekazana sama wartość zmiennej. W takim przypadku wartość zmiennej myNumber ciągle jest taka sama. Jak w takim razie za pomocą metody IncrementValue zwiększyć wartość zmiennej myNumber? Musimy do metody IncrementValue przekazać zmienną myNumber przez referencje. Aby to zrobić, musimy użyć słowa kluczowego ref lub out.
Jak użyć słowa kluczowego ref?
W sygnaturze metody IncrementValue musisz oznaczyć parametr słowem ref oraz przy wywołaniu tak samo musisz dodać słowo kluczowe ref.
using System;
namespace Demo
{
class Program
{
static void Main()
{
int myNumber = 0;
IncrementValue(ref myNumber);
IncrementValue(ref myNumber);
IncrementValue(ref myNumber);
Console.WriteLine(myNumber);//3
}
public static void IncrementValue(ref int value)
{
value++;
}
}
}
Jak użyć słowa kluczowego out?
using System;
namespace Demo
{
class Program
{
static void Main()
{
int myNumber;
IncrementValue(out myNumber);
IncrementValue(out myNumber);
IncrementValue(out myNumber);
Console.WriteLine(myNumber);//11
}
public static void IncrementValue(out int value)
{
value = 10;
value++;
}
}
}
Jak widzisz, w tym przypadku out nie ma zbyt dużego sensu, jednak możesz go użyć podobnie jak ref. To znaczy, gdy chcesz użyć słowa kluczowego out, to musisz oznaczyć parametr w sygnaturze tym słowem oraz przy wywołaniu metody również musisz argument poprzedzić słowem kluczowym out.
Skoro inicjalizacja przed przekazaniem do metody jest zbędna, to również możesz wywołać metodę w ten sposób:
static void Main()
{
IncrementValue(out int myNumber);
Console.WriteLine(myNumber);
}
ref vs out – jaka jest różnica pomiędzy ref i out?
Jak na pewno zdążyłeś zauważyć, oba sposoby trochę się od siebie różnią, wynika to z tego, że każdy z nich będzie bardziej dopasowany do innej sytuacji. Podstawowe różnice pomiędzy nimi:
- Zmienna oznaczona słowem ref musi być zainicjalizowana przed przekazaniem jej jako parametr. U nas: "int number = 0;".
- Zmienna oznaczona słowem out nie musi (ale może) być zainicjalizowana przed przekazaniem jej jako parametr. U nas: "int number;". Również może być inicjalizacja przed przekazaniem, lecz nie ma to najmniejszego sensu.
- Zmienna oznaczona przez ref nie musi zostać zainicjalizowana w metodzie. U nas dopuszczalny był sam zapis: "value++;".
- Zmienna oznaczona przez out musi zostać zainicjalizowana w metodzie. U nas zmienna oprócz inkrementacji musiała najpierw zostać zainicjalizowana: "value = 10; value++;".
Który sposób, w jakiej sytuacji użyć?
Zmienna oznaczona przez ref mówi nam, że zmienna została już wcześniej zainicjalizowana i może zostać odczytana lub/i zmieniona w metodzie, a wszystkie zmiany będą widoczne również poza metodą. Zmienna oznaczona przez out mówi nam, że zmienna nie została jeszcze zainicjalizowana, nie ma żadnej wartości. Jej wartość będzie zainicjalizowana wewnątrz metody i zazwyczaj używamy w przypadkach, gdy chcemy, żeby wartość jakiejś zmiennej została zmieniona poza metodą.
PODSUMOWANIE
Także jak widzisz, mimo że ref i out z pozoru mają takie samo zastosowanie, to każde z nich będzie przydane w innej sytuacji. Ref używamy, gdy interesuje nas zarówno wartość zmiennej, która została nadana przed przekazaniem do metody, jak i wartość po wyjściu z tej metody, a out, gdy interesuje nas tylko wartość po wyjściu z metody (jak sama nazwa wskazuje). Jak wspomniałem na wstępie, takie pytanie może ukazać się na Twojej rozmowie kwalifikacyjnej na stanowisko młodszego programisty C#/.NET, jeżeli interesują Cię inne takie pytania, to daj znać w komentarzu. Możesz też zerknąć na dokument, w którym znajdziesz najczęstsze 10 pytań wraz z odpowiedziami, które miałem na rozmowach kwalifikacyjnych (dokument pdf), gdy szukałem pracy na stanowisku młodszego programisty C#.
Poprzedni artykuł - Czy Tak Naprawdę Znasz Różnice Pomiędzy First vs FirstOrDefault vs Single vs SingleOrDefault?.
Następny artykuł - Zanim Zaczniesz Programować – Instalacja i Zapoznanie z Visual Studio