MySQL Java JavaScript PHP Python HTML-CSS C-sharp

Structuri

Alături de clase, structurile reprezintă un alt mod de a crea tipuri de date proprii în C#. Mai mult, multe tipuri primitive, de exemplu, int, double etc., de fapt sunt structuri.

Definirea structurii

Pentru definirea unei structuri se folosește cuvântul cheie struct:

struct nume_structura
{
   // elementele structurii
}

După cuvântul struct urmează numele structurii și apoi în acolade sunt plasate elementele structurii - câmpuri, metode etc.

De exemplu, să definim o structură care se va numi Person și care va reprezenta o persoană:

struct Person
{
}

Începând cu versiunea C# 12, dacă structura are o definiție goală (nu conține câmpuri, proprietăți, metode), atunci acoladele după numele tipului pot fi omise:

struct Person;

La fel ca și clasele, structurile pot stoca starea sub formă de câmpuri (variabile) și pot defini comportamentul sub formă de metode. De exemplu, să adăugăm în structura Person câteva câmpuri și o metodă:

struct Person
{
   public string name;
   public int age;

   public void Print()
   {
       Console.WriteLine($"Nume: {name}  Vârstă: {age}");
   }
}

În acest caz sunt definite două variabile - name și age pentru stocarea respectiv a numelui și vârstei persoanei și metoda Print pentru afișarea informațiilor despre persoană pe consolă.

Și la fel ca în cazul claselor, pentru a accesa funcționalitatea structurii - câmpurile, metodele și alte componente ale structurii se folosește notația cu punct - după obiectul structurii se pune un punct și apoi se specifică componenta structurii:

obiect.câmp_structură
obiect.metodă_structură(parametrii_metodei)

Inițializarea cu ajutorul constructorului

Pentru a folosi structura este necesară inițializarea acesteia. Pentru inițializarea creării obiectelor structurii, la fel ca în cazul claselor, se folosește apelul constructorului cu operatorul new.

Chiar dacă în codul structurii nu este definit niciun constructor, structura are cel puțin un constructor - constructorul implicit, care este generat de compilator. Acest constructor nu acceptă parametri și creează obiectul structurii cu valori implicite.

new nume_structură();

De exemplu, să creăm un obiect al structurii Person cu ajutorul constructorului implicit:

Person tom = new Person();  // apelul constructorului
// sau așa
// Person tom = new();

tom.name = "Tom";   // schimbăm valoarea implicită în câmpul name

tom.Print();    // Nume: Tom  Vârstă: 0

struct Person
{
   public string name;
   public int age;

   public void Print()
   {
       Console.WriteLine($"Nume: {name}  Vârstă: {age}");
   }
}

În acest caz se creează obiectul tom. Pentru crearea lui se apelează constructorul implicit, care stabilește valori implicite pentru câmpurile sale. Pentru datele numerice, aceasta valoare este 0, astfel că câmpul age va avea valoarea 0. Pentru șiruri de caractere, aceasta valoare este null, care indică lipsa valorii.

Dar ulterior, dacă câmpurile sunt accesibile (și în acest caz, deoarece au modificatorul public sunt accesibile), putem schimba valorile lor. Astfel, aici câmpului name i se atribuie șirul de caractere "Tom". Respectiv, la executarea metodei Print() vom obține următoarea afișare pe consolă:

Nume: Tom  Vârstă: 0

Inițializarea directă a câmpurilor

Dacă toate câmpurile structurii sunt accesibile (ca în cazul câmpurilor structurii Person, care au modificatorul public), structura poate fi inițializată fără a apela constructorul. În acest caz este necesar să atribuim valori tuturor câmpurilor structurii înainte de a accesa valorile câmpurilor și de a apela metodele structurii. De exemplu:

Person tom;         // nu apelăm constructorul
// inițializarea câmpurilor
tom.name = "Sam";
tom.age = 37;

tom.Print();    // Nume: Sam  Vârstă: 37

struct Person
{
   public string name;
   public int age;

   public void Print()
   {
       Console.WriteLine($"Nume: {name}  Vârstă: {age}");
   }
}

Inițializarea câmpurilor implicite

Este de menționat că începând cu versiunea C# 10, putem inițializa direct câmpurile structurii la definirea lor (până la C# 10 acest lucru nu era posibil):

Person tom = new Person();
tom.Print();    // Nume:Tom  Vârstă: 1

struct Person
{
   // inițializarea câmpurilor cu valori implicite - disponibilă începând cu C# 10
   public string name = "Tom";
   public int age = 1;
   public Person() { }
   public void Print() => Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

Cu toate acestea, chiar și în acest caz, în ciuda valorilor implicite, este necesar să definim și să apelăm explicit constructorul dacă dorim să folosim aceste valori.

Constructorii structurii

La fel ca și clasa, structura poate defini constructori. De exemplu, să adăugăm în structura Person un constructor:

Person tom = new();
Person bob = new("Bob");
Person sam = new("Sam", 25);

tom.Print();    // !!!! Nume:   Vârstă: 0
bob.Print();    // Nume: Bob  Vârstă: 1
sam.Print();    // Nume: Sam  Vârstă: 25

struct Person
{
   public string name;
   public int age;

   public Person(string name = "Tom", int age = 1)
   {
       this.name = name;
       this.age = age;
   }
   public void Print() => Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

În acest caz în structura Person este definit un constructor cu doi parametri, pentru care sunt furnizate valori implicite. Totuși, atenție la crearea primului obiect al structurii:

Person tom = new(); // se folosește în continuare constructorul fără parametri implicit
tom.Print();    // !!!! Nume:   Vârstă: 0

Aici se folosește în continuare constructorul implicit, pe când la inițializarea celorlalte două variabile ale structurii se folosește constructorul definit explicit.

Totuși, începând cu versiunea C# 10, putem defini propriul constructor fără parametri:

Person tom = new();

tom.Print();    // Nume: Tom  Vârstă: 37

struct Person
{
   public string name;
   public int age;

   public Person()
   {
       name = "Tom";
       age = 37;
   }
   public void Print() => Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

Este de remarcat că până la versiunea C# 11, la definirea constructorului, structura trebuia să inițializeze toate câmpurile structurii, începând cu versiunea C# 11 acest lucru nu este obligatoriu.

În cazul în care trebuie să apelăm constructori cu diferite numere de parametri, putem, la fel ca în cazul claselor, să îi apelăm în lanț:

Person tom = new();
Person bob = new("Bob");
Person sam = new("Sam", 25);

tom.Print();    // Nume: Tom  Vârstă: 1
bob.Print();    // Nume: Bob  Vârstă: 1
sam.Print();    // Nume: Sam  Vârstă: 25

struct Person
{
   public string name;
   public int age;

   public Person() : this("Tom")
   { }
   public Person(string name) : this(name, 1)
   { }
   public Person(string name, int age)
   {
       this.name = name;
       this.age = age;
   }
   public void Print() => Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

Afișarea pe consolă a programului:

Nume: Tom Vârstă: 1 
Nume: Bob  Vârstă: 1 
Nume: Sam  Vârstă: 25

Începând cu versiunea C# 12, pentru structuri, la fel ca și pentru clase, se pot defini constructori primari. Constructorii primari permit adăugarea de parametri la definirea clasei/structurii și utilizarea acestor parametri în interiorul clasei/structurii:

var tom = new Person("Tom", 38);
tom.Print();

public struct Person(string name, int age)
{
   public Person(string name) : this(name, 18) { }
   public void Print() => Console.WriteLine($"nume: {name}, vârstă: {age}");
}

Aici pentru structura Person este definit un constructor primar cu doi parametri - name și age. În spatele scenei, pentru fiecare parametru al constructorului primar, în clasă se creează un câmp privat care stochează valoarea parametrului. Datorită acestui fapt, ele pot fi folosite în corpul clasei.

În plus față de constructorii primari, clasa poate defini constructori suplimentari, ca în exemplul de mai sus. Dar acești constructori suplimentari trebuie să apeleze constructorul primar:

public Person(string name) : this(name, 18) { }

Inițializatorul structurii

De asemenea, la fel ca și pentru clasă, se poate folosi inițializatorul pentru crearea structurii:

Person tom = new Person { name = "Tom", age = 22 };

tom.Print();    // Nume: Tom  Vârstă: 22

struct Person
{
   public string name;
   public int age;
   public void Print() => Console.WriteLine($"Nume: {name}  Vârstă: {age}");
}

La folosirea inițializatorului, mai întâi se apelează constructorul fără parametri: dacă nu am definit explicit constructorul fără parametri, se apelează constructorul implicit. Apoi câmpurilor sale li se atribuie valorile corespunzătoare.

Copierea structurii cu ajutorul operatorului with

Dacă trebuie să copiem într-un obiect al structurii valorile din alt obiect cu mici modificări, putem folosi operatorul with:

Person tom = new Person { name = "Tom", age = 22 };
Person bob = tom with { name = "Bob" };
bob.Print();    // Nume: Bob  Vârstă: 22

În acest caz, obiectul bob primește toate valorile obiectului tom, iar apoi, după operatorul with, în acolade sunt indicate câmpurile cu valorile pe care dorim să le schimbăm.

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