CodeGym /Kurslar /C# SELF /Təmiz funksiyalar və dəyişməzlik

Təmiz funksiyalar və dəyişməzlik

C# SELF
Səviyyə, Dərs
Mövcuddur

1. Giriş

Təmiz funksiya — eyni giriş verilənlərində həmişə eyni nəticəni qaytaran və heç bir yan təsir törətməyən funksiyadır. Sadə desək: təmiz funksiya ətrafı "korlamır" və xaricdən təsirlənmir.

Funksiya təmiz hesab olunur, əgər:

  • O, yalnız giriş arqumentlərinə əsasən qiymət hesablayır.
  • Xarici dəyişənləri və ya proqramın vəziyyətini dəyişdirmir.
  • Dəyişə bilən xarici dəyişənlərə və ya vəziyyətlərə asılı deyil.

Təmizliyin iki qızıl qaydası

  1. Deterministiklik: eyni giriş — eyni çıxış.
  2. Yan təsirlərin olmaması: funksiya özündən kənarda heç nəyi dəyişmir: faylları, qlobal dəyişənləri, istifadəçi interfeysini (salam, Console.WriteLine).

Din deyil, ağıl

Bu akademik bir ovuc quyruq kimi görünə bilər, amma praktika göstərir:

  • Təmiz funksiya proqnozlaşdırılandır. Onu test etmək asandır — müəyyən arqumentlə çağırsınız və müəyyən nəticə əldə edirsiniz.
  • Təmiz funksiyanı kodda sərbəst "daşına" bilərsiniz, heç nəyin harasa qırılacağından qorxmaq lazım deyil.
  • Çoxnüvəli dünyada təmiz funksiya təhlükəsizdir: onu paralel işlətmək olar, data race-dən qorxmadan.

2. Təmiz və natəmiz funksiyalara nümunələr

Təmiz funksiya: hər şey proqnozlaşdırılandır

// Təmiz funksiya: özündən kənarı toxunmur
int Add(int a, int b)
{
    return a + b;
}

int Square(int x)
{
    return x * x;
}

Add(2, 3) yüz dəfə çağırılsa da — həmişə 5 olacaq. Sıkıcı, amma etibarlıdır.

Natəmiz funksiya: qaydaları pozur

// Təmizliyi pozur: xarici vəziyyətdən asılıdır (statik dəyişən)
int counter = 0;

int Increase()
{
    counter++;
    return counter;
}

Burada Increase() hər çağırışda yeni dəyər qaytaracaq — yəni artıq deterministik deyil.

// Təmizliyi pozur: xarici effekt yaradır (ekrana çap)
int AddAndPrint(int a, int b)
{
    int sum = a + b;
    Console.WriteLine(sum); // Yan təsir!
    return sum;
}

Təsadüfi və zamanla bağlı nə olar?

DateTime.Now və ya Random istifadə edən hər funksiya artıq təmiz deyil:

// Təmiz deyil!
int GetRandomNumber()
{
    return new Random().Next();
}

Fərqlərin cədvəli

Xüsusiyyət Təmiz funksiya Natəmiz funksiya
Eyni arqumentlər üçün həmişə eyni nəticə Bəli Xeyr
Yan təsirlər Xeyr Bəli
Xarici vəziyyətdən asılılıq Xeyr Bəli

3. Məlumatların dəyişməzliyi: nəzəriyyə və praktik

Dəyişməzlik (immutability) — obyekt yaradıldıqdan sonra onu dəyişmək mümkün olmadığı yanaşmadır. Yeni dəyərə ehtiyac varsa — yeni obyekt yaradırıq.

Niyə bu vacibdir?

  • Tətbiq təsadüfi məlumat dəyişikliyinə daha davamlı olur.
  • Gizli "dəyişiklik sızmaları" olmur: əgər sizdə bir obyekt varsa, heç kim onun sahəsini gizlicə dəyişməyəcək.
  • Dəyişməzlik bir çox avtomatik optimizasiyaların və paralel hesablamaların əsasıdır.

C#-də sadə nümunələr

.NET-də dəyişməz tiplər

C#-da sətirlər (string) dəyişməzdir! Hər dəfə string.Concat(s, "world") etdikdə yeni sətir yaranır.

string s = "Hello";
string t = s;
s = s + " World";
Console.WriteLine(t); // t == "Hello"

Massivlər və kolleksiyalar: default üzrə mutable

int[] numbers = { 1, 2, 3 };
numbers[0] = 42; // Massiv dəyişdi!

Dəyişməzliyi "barmaqla izah": kodun kompilyasiyası

Mövcud obyekt/dəyəri dəyişdirmək əvəzinə yeni qaytarırıq:

// Bunun əvəzinə:
void AddToList(List<int> list, int value)
{
    list.Add(value); // Mutasiya edir!
}

// Daha yaxşı:
List<int> AddToList(List<int> list, int value)
{
    var newList = new List<int>(list) { value }; // Yeni siyahı
    return newList;
}

İllüstrasiya: dəyişdir — dəyişdirmə

flowchart LR
    A[İlkin obyekt] --"mutasiya"--> B[eyni obyekt, amma içi fərqli]
    A --"dəyişməzlik"--> C[yeni obyekt]

4. Real C# kodunda niyə lazım?

  • Müasir C# kitabxanaları kimi LINQ, Entity Framework və ASP.NET Core təmiz funksiyalar və dəyişməzliyə önəm verirlər.
  • Dəyişməzlik "sehrli" xətaların sayını azaldır, kiminsə haradasa vacib dəyəri sildiyi hallar azalır.
  • Təmiz funksiyalar unit-testləri asanlaşdırır, çünki testi yazmaq üçün yalnız giriş və çıxışı yoxlamaq kifayətdir, xarici dünya ilə məşğul olmaq lazım deyil.

Nümunə: sətirlərlə işləmək

string s = "Hello";
string newS = s.Replace("H", "J"); // s hələ də "Hello"; newS — "Jello"

Nümunə: LINQ və kolleksiyalar

Where, Select və digər metodlar yeni kolleksiyalar qaytarır, köhnələri toxunmur.

var numbers = new List<int> { 1, 2, 3, 4 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

// numbers olduğu kimi qaldı!

Real həyatdan nümunə: konfiqurasiya dəyişməz obyektlərlə

Bir çox müasir .NET API-ləri konfiqurasiya üçün dəyişməz obyektlərdən istifadə edir, məsələn JsonSerializerOptions:

var options = new JsonSerializerOptions
{
    WriteIndented = true
};
// Bu obyekt "oyun zamanı" dəyişmir, bu etibarlılığı artırır.

5. Tipik səhvlər və tələlər

Sürüşkən yer o zaman başlayır ki, siz "təmiz" kodda təsadüfən məlumatı mutasiya edirsiniz.

Bu çox vaxt kolleksiyalarla olur: siyahını filterləmək istədiniz, amma prosesdə ilkin siyahını dəyişdiniz.

Yaxud unutdunuz ki, List<T>.Add metodu obyekti yerindəcə dəyişdirir.

Pis nümunə:

List<int> DoubleTheNumbers(List<int> xs)
{
    // Səhv! İlkin siyahını mutasiya edirik, eyni obyekti qaytarırıq.
    foreach (var i in xs)
        xs.Add(i * 2);
    return xs;
}

Bu kod icra zamanı xətaya (InvalidOperationException) səbəb olacaq, çünki biz kolleksiyanı iterasiya edərkən dəyişdiririk — mutasiyanın klassik problemi.

Düzgün:

List<int> DoubleTheNumbers(List<int> xs)
{
    var newList = new List<int>(xs.Select(x => x * 2));
    return newList;
}
2
Tapşırıq
C# SELF, səviyyə, dərs
Bağlanıb
Dəyişməz ədədlər siyahısı
Dəyişməz ədədlər siyahısı
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION