CodeGym /Kurslar /C# SELF /Kompilyator xəbərdarlıqlarının analizi

Kompilyator xəbərdarlıqlarının analizi

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

1. Giriş

Təsəvvür elə ki, proqram kodu — bir tamaşadır, dəyişənlər isə aktyorlardır. Hər dəfə dəyişən yeni səhnəyə (kod bloku) çıxanda, o ya "canlı" olur (dəyəri var), ya da "ruh" (null). Amma problem ondadır ki, tamaşaçı — kompilyator — tamaşanı canlı yox, ssenariyə baxaraq izləyir. O görür ki, aktyorlara rollar harada verilir (dəyər təyin olunur), harada yoxa çıxırlar (null olurlar). Amma reallığa (proqramın icrasına) baxa bilmir — yalnız ssenariyə əsasən təxmin edə bilər!

Data flow-un statik analizi — bu prosesdir ki, kompilyator proqram işə düşməmişdən əvvəl kodu yoxlayır ki, birdən kimsə "NullReferenceException ilə yıxılma səhnəsi" oynamaq istədi.

Prosesin mahiyyəti

C# 8.0-dan və Nullable Reference Types (NRT) rejimi gələndən kompilyator yoxlayır ki, dəyişən hansısa icra yolunda null ola bilər ya yox. Əgər ola bilərsə — dərhal xəbər verir. Yəni sənə "birdən aktyor ruh oldu, adını istifadə etmə" deməyə imkan vermir.

2. Kompilyatorun xəbərdarlıqlarını necə oxumaq lazımdır

Əsas xəbərdarlıq kateqoriyaları

NRT rejimi aktiv olanda, kompilyator xüsusilə referans dəyişənləri (string, User, massivlər, obyektlər) diqqətlə izləyir. Ən çox rast gəlinən xəbərdarlıq tipləri bunlardır:

  • Possible null assignment — sən null ola biləcək dəyəri, null qəbul etməyən dəyişənə təyin etməyə çalışırsan.
  • Dereference of a possibly null reference — obyektin üzvünə müraciət edirsən, amma kompilyator əmin deyil ki, o null deyil.
  • Possible null return — metod null qaytara bilər, halbuki imzasına görə dəyər qaytarmalıdır.
  • Nullable object must have a value — sən nullable tipdə .Value istifadə edirsən, amma yoxlamadan.
  • Unassigned non-nullable property — sən null qəbul etməyən sahəyə/sahibə dəyər verməmisən.

Adətən IDE-də (məsələn, Rider və ya Visual Studio) belə xəbərdarlıqlar dalğalı xəttlə vurğulanır, siçanla üstünə gələndə izah çıxır.

Tipik xəbərdarlıq nümunəsi


#nullable enable

string? possibleNull = GetString();

// Ay-ay, kompilyator deyinir: "Dereference of a possibly null reference"
int length = possibleNull.Length; // Xəbərdarlıq!

Kompilyator əmin deyil ki, possibleNull null deyil, yəni .Length çağırışı istisna ata bilər.

Əgər metod belədirsə:

string? GetString() { ... }

Və sən belə yazırsan:

string nonNullable = GetString();

Onda xəbərdarlıq alırsan: null non-nullable dəyişənə təhlükəli ötürülə bilər.

3. Kompilyator kodunu analiz edir

Nümunə 1: düz təyinat


string? name = null;
Console.WriteLine(name.Length); // Xəbərdarlıq: null-a müraciət ola bilər

Burada hər şey aydındır: name null-dır, deməli property-ə müraciət təhlükəlidir.

Nümunə 2: null yoxlaması


string? name = GetUserName();

if (name != null)
{
    Console.WriteLine(name.Length); // Hər şey ok!
}
else
{
    Console.WriteLine("Ad göstərilməyib!");
}

Kompilyator başa düşür ki, if (name != null) blokunda dəyişən təhlükəsiz sayılır. Bu da flow analysis — şərtlərə görə dəyərlərin axınının analizidir.

4. Kompilyator "metodun içinə" baxa bilmir

O, yalnız imzaya baxır — əgər yazılıb ki, metod string? qaytarır, o inanır ki, null ola bilər, hətta içəridə həmişə string qaytarılsa belə.

Nümunə 3: metoddan dəyər qaytarmaq


string? GetMaybeName(bool useName)
{
    if (useName)
        return "Code Jedi";
    else
        return null;
}

void PrintLength()
{
    string? name = GetMaybeName(false);

    Console.WriteLine(name.Length); // Xəbərdarlıq!
}

Kompilyator görür ki, GetMaybeName ola bilər null qaytarsın, ona görə də diqqətli olmağını istəyir.

5. Yayğın ssenarilər və xəbərdarlıqlar

Nullable dəyişəni non-nullable dəyişənə təyin etmək


string? maybeUser = GetUser();
string alwaysUser = maybeUser; // warning: possible null assignment

Xəbərdarlığı aradan qaldırmaq üçün:


string alwaysUser = maybeUser ?? "Qonaq";

İndi həmişə string olacaq — ya metoddan, ya da "Qonaq".

Nullable value-type üçün .HasValue yoxlamasını unutmaq


int? age = GetAge();
int realAge = age.Value; // warning: null-a müraciət ola bilər

Ya belə et:


if (age.HasValue)
    Console.WriteLine(age.Value);

Ya da:


int realAge = age ?? -1;

İlkinləşdirilməmiş avtomatik property-lər


class User
{
    public string Name { get; set; } // warning: ilkinləşdirilməyib!
}

Həllər:


public string Name { get; set; } = "Adsız";

və ya


public string? Name { get; set; }

6. Flow analizinin çətin halları

Döngülərdə analiz


string? text = null;

while (text == null)
{
    text = Console.ReadLine();
}

Console.WriteLine(text.Length); // hər şey ok: kompilyator başa düşdü!

Müxtəlif təyinat yolları


string? name;
if (Random.Shared.Next() % 2 == 0)
    name = "Alice";
else
    name = null;

Console.WriteLine(name.Length); // warning: possible null dereference

Kompilyator bütün yolları analiz edir. Əgər heç olmasa birində null varsa — xəbərdarlıq verir.

7. Kompilyatoru necə "sakitləşdirmək" olar (və nə vaxt bunu etməmək lazımdır)

Bəzən sən əminsən ki, dəyər null ola bilməz, amma kompilyator inanmır:


string? value = GetSomething();
if (value == null)
    throw new Exception("Dəyər gözlənilirdi!");

Console.WriteLine(value.Length); // Xəbərdarlıq yox olur

Və ya sən ! operatorundan istifadə edirsən:


string? value = GetSomething();
Console.WriteLine(value!.Length); // Xəbərdarlıq yoxdur, amma təhlükəlidir

Buna null-forgiving operator deyilir. O heç nə yoxlamır — sadəcə kompilyatora deyir: "sakit ol, hər şey nəzarətdədir". Amma səhv etsən — runtime-da istisna alacaqsan.

1
Sorğu/viktorina
, səviyyə, dərs
Əlçatan deyil
Nullable-tiplər
Nullable Reference Types-ə giriş
Şərhlər
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION