După cum sugerează și numele acestora, modificatorii de acces sunt niște concepte de programare care pot modifica nivelul de acces al unor elemente. În cuvinte mai complexe, modificatorii de acces sunt cuvinte cheie rezervate care adaugă informații pentru compilator și bucata de cod aferentă modificatorilor respectivi.
Probabil că pentru moment vi se par abstracți, dar vom vedea că nu sunt. Deci, în C#, avem 4 modificatori de acces – public, privat, protejat și intern.
Cum folosim modificatorii de acces? Ei bine, am făcut-o deja în câteva dintre exemplele noastre anterioare. Țineți minte această linie de cod?
1 2 |
public void Porneste() ... |
Sau aceasta?
1 2 |
private int greutate; ... |
Ei bine, acolo i-am folosit! Am folosit modificatorii de acces public și privat.
Îi voi explica mai înainte de toate, după care îi voi exemplifica.
- Nivel de acces public (public) – spune compilatorului că elementul poate fi accesat din orice clasă, proprietate, metodă etc. din namespace-ul curent (vom învăța despre namespace în viitor). Poate fi asociat și lipsei oricărei restricții de acces. Este cel mai puțin restrictiv modificator de acces.
- Nivel de acces privat (private) – definește cele mai restrictive permisiuni de acces din C#. Orice element care este declarat folosind modificatorul de acces privat poate fi folosit numai în interiorul clasei în care a fost declarat. Acesta este modificatorul de nivelului de acces implicit.
- Nivel de acces intern (intern) – specifică faptul că elementele declarate vor fi accesibile numai din același namespace.
- Nivel de acces protejat (protected) – elementele vor fi accesibile în clasa în care sunt declarate și în instanțele claselor derivate. Vom învăța despre moștenirea claselor în viitor.
Modificatorii de acces pot fi utilizați numai în fața următoarelor elemente: declarație de clasă, câmpuri, proprietăți și metode. După cum vă puteți imagina, ele pot fi folosite pentru a modifica accesul (vizibilitatea) elementelor în fața cărora sunt plasate. În lecția noastră anterioară, instanțierea, am adăugat un nou fișier clasă la proiectul nostru, numit Cuptor și conținând, printre altele, aceste coduri:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
class Cuptor { private string culoare; public string Culoare { get { return this.culoare; } set { this.culoare = value; } } public Cuptor() // Constructor implicit { this.culoare = "Gri"; } public void Porneste() // Metoda Porneste { Console.WriteLine("Cuptorul este pornit!"); } public void Opreste() { Console.WriteLine("Cuptorul este oprit!"); } } |
Apoi, în fișierul Program.cs, l-am instanțiat astfel:
1 2 3 4 5 6 7 8 9 |
class Program { static void Main(string[] args) { Cuptor copieCuptor = new Cuptor(); Console.WriteLine(copieCuptor.Culoare); Console.Read(); } } |
Deci, odată ce am creat o instanță a clasei noastre Cuptor, putem începe să îi accesăm membrii, proprietățile, metodele etc., cum ar fi de exemplu, proprietatea Culoare, în exemplul nostru. Motivul pentru care proprietatea Culoare poate fi accesată în acest fel, sau motivul pentru care îi putem atribui o valoare este acela că, atunci când am declarat-o, am folosit cuvântul cheie public în fața declarației sale. Procedând astfel, acea proprietate poate fi accesată nu numai în interiorul clasei în care am declarat-o (clasa Cuptor), ci și din alte clase, cum de exemplu i-am citit valoarea din interiorul metodei Main(), aflată în clasa Program.
Pe de altă parte, câmpul numit culoare a fost declarat utilizând modificatorul de acces private, ceea ce înseamnă că acesta poate fi accesat numai în interiorul clasei în care a fost declarat. Deci, îl putem accesa perfect din interiorul clasei Cuptor:
1 2 3 4 5 6 7 8 9 10 |
class Cuptor { private string culoare; public string Culoare { get { return this.culoare; } set { this.culoare = value; } } } |
Dar nu din afara ei:
1 2 3 4 5 6 7 8 9 |
class Program { static void Main(string[] args) { Cuptor copieCuptor = new Cuptor(); Console.WriteLine(copieCuptor.culoare); Console.Read(); } } |
Observați în exemplul de mai sus că am încercat să afișăm pe consolă NU proprietatea Culoare (cu majuscula C), care este publică – prin urmare accesibilă, ci câmpul culoare (cu minuscula c), declarat private. Din acest motiv, compilatorul va afișa următoarea eroare: „Cuptor.culoare” este inaccesibil datorită nivelului său de protecție (‘Cuptor.culoare’ is inaccessible due to its protection level).
Din moment ce nu am învățat încă despre namespace, nu trebuie să vă preocupați de modificatorii de acces intern și protected. Ei sunt folosiți oricum doar în situații speciale. De asemenea, trebuie să știți că există o combinație a celor doi, modificatorul de acces protected intern, dar pentru moment, tratați-l doar ca un element de cultură generală.
Este de asemenea un moment bun să vă informez că nu este obligatoriu să avem clasele noastre în fișiere individuale. Așadar, am fi putut crea clasa Cuptor fără a crea un fișier separat pentru ea, astfel:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System; using System.IO; namespace BunaLume { class Program { static void Main(string[] args) { Cuptor copieCuptor = new Cuptor(); Console.WriteLine(copieCuptor.Culoare); Console.Read(); } } class Cuptor { private string culoare; public string Culoare { get { return this.culoare; } set { this.culoare = value; } } public Cuptor() // constructor implicit { this.culoare = "Gri"; } public void Porneste() // Metoda Porneste { Console.WriteLine("Cuptorul estepornit!"); } public void Opreste() { Console.WriteLine("Cuptorul este oprit!"); } } } |
Acest lucru vă va ajuta să înțelegeți mai bine faptul că claselor (obiectelor), nu le pasă unde sunt declarate atât timp cât se află în interiorul corpului unui namespace. Motivul pentru care am declarat clasa Cuptor într-un fișier separat a fost acela că în proiecte mari vă va fi mult mai ușor să păstrați codurile mai organizate, păstrând fiecare dintre clasele voastre în fișiere separate ale proiectului vostru, fiecare având propriul nume (de preferință, același cu al clasei). Imaginați-vă haosul pe care l-ați avea dacă proiectul vostru ar avea 50 de clase în fișierul Program.cs …
Deci, pentru a încheia lecția noastră, acum că știm că mai multe clase pot locui într-un singur fișier, atât timp cât sunt plasate în interiorul namespace, să luăm în considerare următorul cod:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
using System; using System.IO; namespace BunaLume { class Program { static void Main(string[] args) { Cuptor copieCuptor = new Cuptor(); copieCuptor.Opreste(); copieCuptor.Porneste(); Console.Read(); } } class Cuptor { public void Porneste() { Console.WriteLine("Cuptorul este pornit!"); } private void Opreste() { Console.WriteLine("Cuptorul este oprit!"); } public Cuptor() // constructor implicit { Opreste(); Porneste(); } } } |
Deci, avem două clase într-un namespace – Cuptor și Program. În interiorul clasei noastre Cuptor declarăm două metode – Porneste() și Opreste(), una publică, una privată. Apoi, în cadrul clasei Program, instanțiem clasa Cuptor și încercăm să accesăm metodele Porneste() și Opreste(). Facem același lucru și în interiorul constructorului clasei Cuptor. Diagrama de acces este descrisă de următoarea imagine:
Metoda Opreste(), fiind declarată privată, este accesibilă în interiorul clasei în care a fost declarată, așa că apelarea ei în interiorul constructorului Cuptor funcționează fără probleme. Cu toate acestea, încercarea de a o apela din clasa Program este interzisă. Pe de altă parte, metoda Porneste(), fiind declarată publică, este accesibilă atât clasei unde a fost declarată, cât și clasei Program.
Prin urmare. Știm acum ce sunt modificatorii de acces privat și public. Pot face anumite elemente vizibile lumii exterioare sau nu. Dar cu ce anume ne ajută acest lucru? De ce ar trebui să ascundem lucruri de lumea exterioară în primul rând? Nu este doar o complicație inutilă?
Nu, nu chiar. Dacă ați creat un joc, ați lucrat ani de zile la el și acum vrei să-l vindeți, trebuie să implementați un tip de licență și un sistem de chei de licență, nu? În plus, programul vostru trebuie să aibă și un fel de metodă în care puteți verifica dacă o licență este validă sau nu. Dacă cheia de licență este bună, apelați o metodă numită StartJoc(), dacă nu, alertați utilizatorul că licența este invalidă. Dar, dacă metoda StartJoc() a fost declarată publică, deci este accesibilă din exteriorul programului vostru, ce ar împiedica un utilizator să o apeleze direct, ocolind verificarea licenței? E oribil, nu-i așa? De aceea, ar trebui să declarați metoda StartJoc() privată, ceea ce ar permite apelarea ei doar din interiorul programului dvs., nu din lumea exterioară.
Un alt motiv pentru care ar trebui să utilizați modificatori de acces este acela că ei pot ascunde date irelevante de lumea exterioară. La fel ca în lumea reală, dacă aveți o mașină, nu sunteți interesați de modul în care funcționează sau de acțiunile sale interne. Sunteți interesat doar de lucrurile relevante, cum ar fi pornirea sau oprirea ei, conducerea, virarea, etc. Nu vă interesează ce pinioane fac posibilă virarea la dreapta sau cum funcționează acestea, sunteți interesați doar de acțiunea de virare la dreapta. Acest principiu se aplică și programării, unde ar trebui să expuneți lumii exterioare numai porțiunile relevante ale codului vostru, nu toate procesele și calculele interne.
În cele din urmă, acest proces de ascundere a datelor irelevante de lumea exterioară se numește încapsulare, care este un principiu fundamental al programării orientate obiect (OOP).
Dacă omiteți specificarea unui modificator de acces, C# va aplica intern în mod automat un modificator, după cum urmează:
- în interiorul metodelor și funcțiilor, modificatorul de acces implicit este private (de fapt compilatorul nu vă permite nici măcar specificarea unui modificator de acces, deoarece private este singurul disponibil în acest caz)
1234567class Cuptor{public void Porneste(){private bool estePornit = false;}}
1234567class Cuptor{public void Porneste(){bool estePornit = false;}} - în interiorul claselor, modificatorul de acces implicit este private:
123456789class Cuptor{bool estePornit = false;public void Porneste(){}}
123456789class Cuptor{private bool estePornit = false;public void Porneste(){}} - în interiorul namespace-urilor, modificatorii de acces impliciți sunt internal. Cu alte cuvinte, codul acesta:
1234567namespace BunaLume{class Cuptor{}}
1234567namespace BunaLume{internal class Cuptor{}}
Tags: încapsularea, modificatori de acces, obiecte, OOP, programarea orientată pe obiecte