MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Verificarea pentru null și operatorii ?. și ??

Verificarea pentru null - Null guard

Dacă urmează să utilizăm o variabilă sau un parametru care poate avea valoarea null, adică reprezintă un tip nullable (nu contează dacă este valoric sau de referință), pentru a evita apariția unei excepții NullReferenceException, putem verifica dacă este null:

void PrintUpper(string? text)
{
   if (text != null)
   {
       Console.WriteLine(text.ToUpper());
   }
}

În acest caz, dacă parametrul text nu este null, apelăm metoda ToUpper() a șirului, care convertește caracterele șirului în majuscule.

De asemenea, cu ajutorul operatorului is putem verifica valoarea unui obiect:

obiect is valoare

Dacă obiectul din stânga operatorului is are valoarea din dreapta operatorului, atunci operatorul is returnează true, altfel returnează false.

De exemplu, verificarea parametrului/variabilei pentru valoarea null:

void PrintUpper(string? text)
{
   if (text is null) return;
   Console.WriteLine(text.ToUpper());
}

Sau, dimpotrivă, putem verifica absența valorii cu ajutorul is not:

void PrintUpper(string? text)
{
   if (text is not null)
       Console.WriteLine(text.ToUpper());
}

De asemenea, putem verifica dacă tipul este cel pe care dorim să-l folosim:

void PrintUpper(string? text)
{
   if (text is string)
       Console.WriteLine(text.ToUpper());
   else
       Console.WriteLine("NULL");
}

Astfel de verificări sunt denumite null guard sau "protecție împotriva null".

Operatorul ??

Operatorul ?? este denumit operatorul de coalescență null. Este utilizat pentru a seta valori implicite pentru tipurile care pot avea valoarea null:

operand_stânga ?? operand_dreapta

Operatorul ?? returnează operandul din stânga dacă acesta nu este null. În caz contrar, returnează operandul din dreapta. Operandul din stânga trebuie să poată avea valoarea null. Să vedem un exemplu:

string? text = null;
string name = text ?? "Tom";  // este egal cu Tom, deoarece text este null
Console.WriteLine(name);    // Tom

int? id = 200;
int personid = id ?? 1; // este egal cu 200, deoarece id nu este null
Console.WriteLine(personid);    // 200

Nu putem scrie astfel:

int x = 44;
int y = x ?? 100;

Aici variabila x reprezintă un tip valoric int și nu poate avea valoarea null, deci nu poate fi folosită ca operand stânga în operația ??.

De asemenea, putem folosi operatorul derivat ??=:

string? text = null;
text ??= "Sam";
// echivalent cu
// text = text ?? "Sam";
Console.WriteLine(text);    // Sam

int? id = 100;
id ??= 1;
// echivalent cu
//id = id ?? 1;
Console.WriteLine(id); // 100

Operatorul condițional null

Uneori, când lucrăm cu obiecte care pot avea valoarea null, putem întâmpina o eroare: încercăm să accesăm un obiect care este null. De exemplu, să presupunem că avem următorul sistem de clase:

class Person
{
   public Company? Company { get; set; }   // locul de muncă
}
class Company
{
   public string? WebSite { get; set; }    // site-ul companiei
}

Obiectul Person reprezintă o persoană. Proprietatea Company reprezintă compania unde lucrează persoana. Dar persoana poate să nu lucreze, deci proprietatea Company este de tip Company?, adică poate avea valoarea null.

Clasa Company, la rândul său, conține proprietatea WebSite, care reprezintă site-ul companiei. Dar compania poate să nu aibă un site propriu. De aceea, această proprietate este de tip string?, adică poate avea valoarea null.

Să presupunem că trebuie să afișăm pe consolă cu litere mari site-ul companiei unde lucrează persoana (dacă, bineînțeles, lucrează și dacă compania are un site). La prima vedere, putem scrie următoarea construcție:

void PrintWebSite(Person? person)
{
   if (person != null)
   {
       if(person.Company != null)
       {
           if(person.Company.WebSite != null)
           {
               Console.WriteLine(person.Company.WebSite.ToUpper());
           }
       }
   }
}
class Person
{
   public Company? Company { get; set; }   // locul de muncă
}
class Company
{
   public string? WebSite { get; set; }    // site-ul companiei
}

În metoda PrintWebSite(), primim un obiect Person? și, pentru a evita excepția NullReferenceException, verificăm pe rând toate valorile utilizate pentru null, astfel încât, la final, să folosim metoda ToUpper() pentru a afișa cu litere mari numele site-ului.

Deși aceasta este o metodă funcțională, pentru un simplu afișaj de șir rezultă o construcție complexă. În realitate, putem simplifica:

void PrintWebSite(Person? person)
{
   if (person != null && person.Company != null && person.Company.WebSite != null)
   {
       Console.WriteLine(person.Company.WebSite.ToUpper());
   }
}

Construcția este mult mai simplă, dar totuși destul de mare. Pentru a o simplifica și mai mult, în C# există operatorul condițional null (Null-Conditional Operator) - operatorul ?.:

obiect?.component

Dacă obiectul nu este null, se accesează componenta obiectului - câmpul, proprietatea, metoda. Dacă obiectul reprezintă valoarea null, accesarea componentei nu are loc.

Aplicăm acest operator, modificând exemplul anterior:

void PrintWebSite(Person? person)
{
   Console.WriteLine(person?.Company?.WebSite?.ToUpper());
}

Astfel, dacă person nu este null, se accesează proprietatea Company. Dacă proprietatea Company nu este null, se accesează proprietatea WebSite a obiectului Company. Dacă proprietatea WebSite nu este null, se apelează metoda ToUpper().

← Lecția anterioară Lecția următoare →