Wednesday, April 24, 2019 04:20

Namespace

În OOP, namespace-urile sunt containere pentru un grup de clase care au un context comun sau sunt clasificate prin funcționalitate comună. Namespace-urile nu au niciun fel de funcționalitate și nu este obligatoriu să le folosiți. Cu toate acestea, ele oferă câteva avantaje, cel mai important fiind abilitatea de a sorta și grupa codul în unități logice.

Să luăm în considerare următorul exemplu: vrem să creăm două obiecte în cod – un robot și un om. Destul de ușor de realizat, până când descoperim că am creat clasa Mana pentru om, dar nu putem crea o altă clasă Mana pentru robot, din cauza unui conflict de nume. Proiectul conține deja o clasă cu acest nume. Cum ar putea diferențieze ce clasă Mana am intenționat să menționăm – a clasei om, sau robot?

Deși acest lucru nu este obligatoriu în C#, este considerată o practică bună să avem clase cu nume identice cu al fișierelor care le conțin, iar namespace-urile ar trebui să aibă același nume ca și dosarele în care locuiesc. În Java, acest lucru este chiar un proces obligatoriu, nu veți putea să vă compilați codul dacă nu respectați această regulă.

Am lucrat cu namespace-uri înainte, de fapt le-am văzut în fiecare dintre lecțiile noastre, deoarece Visual Studio le adaugă automat atunci când creăm o nouă soluție, proiect sau fișier. Puteți testa acest lucru prin adăugarea unei noi clase la proiectul vostru, așa cum am făcut aici. Dacă analizați codul, veți observa că dacă ați adăugat o clasă numită ClasaMea, într-un proiect numit ProiectulMeu, codul din această clasă va arăta astfel:

Și putem instanția această nouă clasă astfel:

Ceea ce nu știți este că numele calificat (întreaga adresă) a clasei este de fapt acesta:

deoarece ClasaMea a fost declarată în namespace-ul ProiectulMeu, prin urmare întreaga sa adresă este ProiectulMeu.ClasaMea. Motivul pentru care compilatorul ne permite să o instanțiem fără a specifica namespace-ul este acela că o instanțiem într-o altă clasă, și ea declarată în același namespace. Și întrucât un namespace poate conține doar o singură clasă cu un nume dat, nu este necesar să se precizeze namespace-ul atunci când folosim acest nume de clasă, compilatorul știe deja că doar o singură clasă cu acest nume poate exista în interiorul său.

Acum, să declarăm noua noastră clasă într-un alt namespace. Modificați numele namespace-ului după cum urmează:

După cum puteți vedea, nu am schimbat foarte mult codul, doar am redenumit namespace-ul. Dar acum, această bucată de cod:

sau această bucată de cod:

va genera o eroare de compilator: Numele sau namespace-ul ‘ClasaMea’ nu există în namespace-ul ‘ProiectulMeu’ (lipsește o referință de asamblare?) (The type or namespace name ‘ClasaMea’ does not exist in the namespace ‘ProiectulMeu’ (are you missing an assembly reference?)). Acest lucru se întâmplă deoarece am redenumit namespace-ul în care este declarată ClasaMea, iar când încercăm să o instanțiem în clasa Program declarată în namespace-ul ProiectulMeu, compilatorul vede că nu există o clasă numită ClasaMea declarată în interiorul unui namespace numit ProiectulMeu.

Pentru a scăpa de această eroare, trebuie să modificăm adresa namespace-ului:

Trebuie să rețineți întotdeauna că atunci când apelați o clasă declarată într-un alt namespace, altul decât cel în care faceți apelul, trebuie să utilizați nume complet calificate (inclusiv namespace). În cuvinte simple, dacă aveți un namespace A, care conține clasele x și y, x poate apela direct y, folosind doar numele clasei; dar dacă aveți două namespace-uri, A conținând clasa x și B conținând clasa y, clasa x poate apela clasa y doar prin specificarea namespace-ului în care este declarată aceasta, și viceversa.

De asemenea, amintiți-vă: clasele trebuie să aibă nume unice numai în namespace-urile în care sunt definite. Putem avea două clase cu același nume, atâta timp cât sunt declarate în namespace-uri diferite.

Namespace-urile pot fi de asemenea, imbricate. Aceasta este o modalitate ușoară de a crea o ierarhie logică, care permite o distribuție și mai precisă a claselor. Calea namespace-urilor imbricate este specificată utilizând operatorul . (punct). Să luăm în considerare următorul exemplu:

Am declarat un namespace System, care conține un namespace Collections, care conține un namespace Generic, care conține o clasă generică numită List. Apoi, am declarat un alt namespace denumit NumeleNamespaceuluiMeu, care conține o clasă numită ClasaMea, în interiorul căreia dorim să instanțiată clasa List pe care am declarat-o anterior.

Așa cum am spus mai sus, deoarece clasa pe care dorim să o instanțiem și clasa în care dorim să instanțiem se află în namespace-uri separate, trebuie să specificăm numele complet calificat:

Începeți să vedeți semnificația acestor nume lungi?

Da, aveți dreptate; acestea sunt namespace-uri și namespace-uri imbricate. E timpul potrivit și pentru a explica directivele using.

Am spus deja că atunci când declarăm două clase în același namespace, nu trebuie să specificăm numele namespace-ului atunci când instanțiem o clasă din cealaltă clasă, deoarece compilatorul presupune deja că facem referire la clasa declarată în același namespace. Cu toate acestea, dacă clasa este declarată într-un alt namespace, trebuie să folosim numele complet calificat. Considerați acest cod:

Observați diferența față de modul obișnuit în care arată codurile noastre? În primul rând, nu avem directive using care să fie utilizate în partea de sus a fișierului nostru. În al doilea rând, am folosit calea complet calificată pentru declarațiile variabilelor int și string. Din aceste două modificări, putem trage următoarea concluzie: directivele using sunt utilizate doar pentru a putea folosi notația scurtă a tipurilor și claselor.

Informații Adiționale


Este posibil să fi observat utilizarea System.Int32 și System.String în numele complet calificat, în loc de System.int și System.string. Acest lucru se datorează faptului că int și string sunt de fapt doar aliasuri pentru System.Int32 și System.String, după cum am explicat aici.

Calea complet calificată a clasei Console este System.Console. Deci, când vrem să scriem ceva pe consolă, ar trebui să o facem în acest mod:

dar întotdeauna scriem așa:

Cuvântul cheie using specifică faptul că programul folosește numele dintr-un namespace dat, în cazul nostru, System. Și deoarece clasa Console este declarată în namespace-ul System, nu este nevoie să specificăm întreaga cale, deoarece linia

spune deja programului nostru că atunci când apelăm o clasă, ar trebui să caute numele acelei clase în interiorul namespace-ului System.

Există însă o consecință a acestui fapt. Luați în considerare următorul cod:

Fiecare dintre namespace-urile de mai sus conține o clasă numită Control. Chiar dacă am importat respectivele namespace-uri cu ajutorul cuvântului cheie using, cum ar putea ști compilatorul la care din ele am făcut referire, dacă vrem să instanțiem clasa Control utilizând notația scurtă? Nu ar ști, și ar genera de fapt această eroare: ‘Control’ este o referință ambiguă între ‘System.Windows.Controls.Control’ și ‘System.Windows.Forms.Control’ (‘Control’ is an ambiguous reference between ‘System.Windows.Controls.Control’ and ‘System.Windows.Forms.Control’). În cazul în care aveți clase cu aceleași nume, chiar dacă utilizați declarații using, trebuie să specificați numele complet calificat, astfel încât compilatorul să știe la ce clasă ați făcut referire.

În încheiere, țineți cont de faptul că directivele using NU sunt recursive! Folosirea instrucțiunii

nu implică și importarea System.Windows.Forms, deși namespace-ul System.Windows.Forms este declarat în interiorul namespace-ului System.Windows.

 

EXERCIȚII
1. Definiți propriul namespace Animale și puneți în el două clase, Pisica și Caine. Definiți încă un namespace și construiți o clasă care să apeleze clasele Pisica și Caine în interiorul său.

Soluție


Creați un nou proiect în Visual Studio, faceți clic dreapta pe dosar și alegeți meniul Add → New Folder. Apoi introduceți numele dosarului și apăsați [Enter], faceți clic dreapta pe dosarul nou creat și selectați Add → New Item…. Din listă, selectați Class, iar pentru numele noii clase introduceți Pisica și apăsați [Add]. Schimbați numele namespace-ului în Animal. Faceți același lucru și pentru clasa Caine.

2. Rescrieți codul următor, asigurându-vă că nu utilizați nicio directivă using :

Soluție


Instrucțiuni: Folosiți nume complet calificate pentru toate tipurile și clasele. Ștergeți directivele using de la începutul fișierului.

Comments

comments

Tags: , ,

Leave a Reply