1. Giriş
Təsəvvür elə ki, bizdə bir funksiya var, hansı ki, istifadəçi barədə (məsələn, adı ilə) həm yaşını, həm qeydiyyat tarixini, həm də aktivlik flag-ını qaytarmalıdır. C və C#-ın köhnə versiyalarında normal sayılırdı ki, funksiya yalnız bir dəyər qaytarsın. Bəs birdən çox dəyər lazımdırsa, nə edək? Bu sual müxtəlif yanaşmaların yaranmasına səbəb oldu və hər birinin öz üstün və çatışmaz tərəfləri var.
Əvvəlki mühazirələrdə artıq körtəjlərlə tanış olmuşduq. İndi isə out-parametrləri öyrənəcəyik və bu iki yanaşmanı müqayisə edəcəyik.
Ən məşhur yanaşmalar:
- out-parametrlərdən istifadə etmək.
- Lazım olan sahələri olan bir obyekt qaytarmaq (anonim tip və ya öz class-ın).
- Körtəj (ValueTuple) qaytarmaq.
Bu mühazirədə biz bu yanaşmalardan ikisini — out-parametrləri və körtəjləri — ətraflı baxacağıq və onları "üz-üzə" müqayisə edəcəyik ki, funksiyadan bir neçə dəyər qaytarmaq üçün hansının daha yaxşı olduğunu anlayaq.
2. out-parametrlər: keçmişdən salam
Belə bir funksiya görəndə:
void GetUserInfo(string userName, out int age, out DateTime registrationDate, out bool isActive)
{
// burada hesablamalar
age = 42;
registrationDate = new DateTime(2010, 1, 1);
isActive = true;
}
adamın ağlına gəlir: bu funksiya yoxsa kiçik bir avtoyuma filialıdır? Hər şey çölə qaytarılır, əsas qaytarılan dəyərdən kənarda!
Necə işləyir
Çağıran kod əvvəlcədən dəyişənləri elan etməlidir ki, funksiya onları doldursun:
int age;
DateTime reg;
bool isActive;
GetUserInfo("Bob", out age, out reg, out isActive);
// İndi bütün dəyişənlər doludur
Console.WriteLine($"{age}, {reg}, {isActive}");
out-yanaşmasının mənfi cəhətləri
- Oxumaq çətindir: Metodun signaturası çox uzanır, qaytarılan məlumatların mənası həmişə parametr adlarından aydın olmur.
- Chain-lərdə narahatlıq: Belə metodu rahatlıqla chain-ə (məsələn, nəticəni birbaşa başqa metoda ötürmək) daxil etmək olmur.
- Dəyişənləri dəyişir: Metod mövcud dəyişənləri dəyişməlidir; əgər out-u unutsaq — compile səhvi olacaq.
- İlkinləşdirmədə gecikmə: Compiler məcbur edir ki, xarici dəyişənləri elan edəsən, hətta nəticəni bir dəfə istifadə etmək istəsən belə.
- Böyük metodlarda oxunaqlılıq zəifdir: Əgər out-parametrlər çoxdursa, asanlıqla qarışdırmaq olar ki, nə nə üçündür və hansı ardıcıllıqla gedir.
Bax, burada körtəjlərin ulduz kimi parladığı yer gəlir.
3. Körtəjlər — yanaşmanın təkamülü
Nümunədə müqayisə edək
Körtəj ilə:
public (int Age, DateTime RegistrationDate, bool IsActive) GetUserInfo(string userName)
{
// bazada axtarışın emulyasiyası
return (42, new DateTime(2010, 1, 1), true);
}
İstifadəsi:
// Bütün dəyərləri birbaşa alırıq və dəyişənlərə ad veririk
var (age, regDate, isActive) = GetUserInfo("Bob");
Console.WriteLine($"{age}, {regDate}, {isActive}");
Artıq elanlar yoxdur, out yoxdur, hər şey maksimum oxunaqlıdır!
Müqayisə cədvəli: out vs tuple
| Kriteriya | Out-parametrlər | Körtəjlər (ValueTuple) |
|---|---|---|
| Signatura | uzun, out-parametrlər siyahıda | kompakt, hər şey bir "bağlama" ilə qaytarılır |
| İstifadə | dəyişənləri elan etmək, sonra metodu çağırmaq lazımdır | birbaşa deconstruct etmək olar |
| Oxunaqlılıq | əgər bir neçə out-parametr varsa, tez-tez itir | elementlərin adları dərhal aydındır |
| Asan kombinə etmək? | yox | bəli, iç-içə və ötürmək olar |
Körtəjlər VS. out — qapağın altında nə baş verir
out-parametrlərlə funksiya əslində öz "ərazisindən" kənarda olan yaddaşla işləyir: bir az sadələşdirsək, o, başqa yerdə yaradılmış dəyişənləri dəyişir. Bu, diqqət tələb edir, çünki təsadüfən dəyişənlərin vəziyyətini "çirkləndirə" bilərsən (compiler-ə təşəkkürlər ki, məcburi mənimsəmə var!).
Körtəj isə — funksiya tərəfindən yaradılan, tam initializasiya olunan və çölə qaytarılan data strukturudur. Yəni, hər şey — bir bağlama, onu yolda itirməyəcəksən və unutmayacaqsan.
Kodun oxunması və dəstəklənməsi
Razılaş ki, bir həftə sonra başqasının koduna baxanda belə görmək istəyirsən:
(var age, var city, var isActive) = GetUserInfo("Anna");
yoxsa
int age;
string city;
bool isActive;
GetUserInfo("Anna", out age, out city, out isActive);
Körtəjlər metodların signaturasını daha az "səs-küylü" edir və istifadənin nəticəsi — intuitiv aydın olur.
4. Körtəjlərin xüsusilə yaxşı olduğu situasiyalar
1. Nəticə və error mesajı qaytarmaq lazım olanda
public (bool Success, string ErrorMessage) TryProcess(string data)
{
if (string.IsNullOrEmpty(data))
return (false, "Məlumat yoxdur");
// məlumatların işlənməsi...
return (true, "");
}
var (ok, error) = TryProcess(input);
if (!ok)
Console.WriteLine($"Xəta: {error}");
2. Bir neçə axtarış nəticəsi qaytaran funksiyalar üçün
public (User? FoundUser, int Index) FindUserByName(User[] users, string name)
{
for (int i = 0; i < users.Length; i++)
{
if (users[i].Name == name)
return (users[i], i);
}
return (null, -1);
}
3. “Cüt” dəyərlər üçün: minimum və maksimum hesablanması
public (int min, int max) FindMinMax(int[] numbers)
{
int min = numbers[0], max = numbers[0];
foreach (var n in numbers)
{
if (n < min) min = n;
if (n > max) max = n;
}
return (min, max);
}
var (minValue, maxValue) = FindMinMax(arr);
GO TO FULL VERSION