A névtér fogalmat a könyvben már párszor emlÃtettem, viszont még egyszer sem volt igazán elmagyarázva, hogy mi is az a névtér? A névtér egy logikai csoportosÃtási lehetÅ‘ség objektum orientált nyelveken belül. Az elÅ‘nyét könnyű egy példával szemléltetni.
Tételezzük fel, hogy többen dolgoznak egy kódon, továbbá tételezzük fel azt is, hogy két programozó ugyanazt a feladatot kapja: implementáljanak egy osztályt. Ebben az esetben nagy a valószÃnűsége annak, hogy ugyanolyan névvel illetik az osztályukat. Egy programon belül névterek nélkül viszont nem lehet két azonos nevű osztály, mivel a fordÃtó nem tudná eldönteni, hogy melyiket is kellene belefordÃtania a végleges termékbe.
Névterek használatával viszont elkerülhetÅ‘ a probléma, mivel a két programozónk két különbözÅ‘ névtérben dolgozik, Ãgy nem adódhat az a probléma, hogy két osztály neve globális szinten ugyanaz legyen. C# esetén a névterek használata kötelezÅ‘. Ennek az oka az, hogy a keretrendszer több száz, vagy ezer osztállyal rendelkezik. Ha nem lennének névterek, akkor azon osztályok nevei, amelyek szerepelnének a keretrendszerben, nem lennének használhatóak.
Ez programozói szempontból egy hatalmas limitáció lenne, mert nem választhatnánk annyira szabadon osztály nevet, valamint a kód karbantarthatósága drasztikusan csökkenne, mivel a különböző funkciót ellátó osztályok ömlesztve, egy névtérben helyezkednének el.
A névtér a csoportosÃtási tulajdonsága által nagyon jó absztraktizáló eszköz amibÅ‘l a kód statikus architektúráját (vázát) szépen fel lehet ismerni. Névterek alapján a megoldandó szoftveres problémának a történetét fel lehet ismerni/el lehet mesélni, különbözÅ‘ mélységekbe lemenve, ha szükség van részletekre.
Egy nagyon jó eszköz a program vázának, arhitektúrájának defininÃciójára, amibe az osztályokat bele kell pakolgatni/fejleszteni különbözÅ‘ architekturális szempontok szerint.
Ilyen szempontok lehetnek az alrendszerek, rétegek, komponensek, osztály definÃciók. A névterek között arhitekturális szabályokat lehet definiálni (megengedett/nem megengedett függÅ‘ségek) és ezek betartását akár tesztekben, akár fordÃtási idÅ‘ben lehet ellenÅ‘rizni, ezáltal is növelve a karbantarthatóságot/módosÃthatóságot.
Összefoglalva tehát a névterek használata segÃti a kód karbantarthatóságát és egy logikai csoportosÃtási sémát biztosÃt.
A .NET keretrendszer osztályai a System névtérben és annak al-névtereiben helyezkednek el. Az egyes al-névterek közötti elválasztásra a pont karakter használható. Visual Studio-ban, ha a programunkon belül létrehozunk egy mappát (Solution Explorerben projekt kijelöl, majd jobb kattintás: Add→ New Folder) és azon belül egy osztályt, akkor a létrehozott osztály már egy saját névtérben fog elhelyezkedni, ami a következőképpen lesz elnevezve:
projekt.mappa
Az elnevezési séma természetesen tovább folytatódik további mappák létrehozásával a mappán belül.
A létrehozott névtereket a using kulcsszóval lehet használatba venni. A korábbi példákban eddig csak a System névteret alkalmaztuk, mivel ebben helyezkedtek el a használt osztályok. A generált osztályunk azonban több using direktÃvával is rendelkezik. Ezek alapértelmezetten kijelölésre kerülnek. A nem használt névterek könnyen eltávolÃthatóak.
Ezen funkció automatizálható Visual Studio-ban úgy, hogy egy tetszÅ‘leges using utasÃtást tartalmazó sorra pozicionáljuk a kurzort, majd jobb gombbal kattintunk. A megjelenÅ‘ menüben pedig az Organise Usings menübÅ‘l válasszuk ki a Remove and Sort Usings opciót.
Ez eltávolÃtja a nem használt névtereket, azokat, amiket pedig használunk, ABC sorrendbe teszi. Ezen opciót ne alkalmazzuk az osztály elsÅ‘ változatának elkészÃtése közben, mert késÅ‘bb manuálisan fel kell vennünk ezeket, illetve az automatikus kód kiegészÃtés is csak a használt osztályokra fog korlátozni.
A globális névtér
C# esetén az összes névtér egy globális névtérbÅ‘l származik, amit a global kulcsszó jelöl. Mi ide kódot nem tudunk elhelyezni, illetve az itt található osztályokat, tÃpusokat sem érhetjük el. A global kulcssszót a névterek teljes elérési nevén való meghatározáshoz használhatjuk.
Erre akkor lehet szükségünk, ha a programunkban több szerelvényből valahogy névtér ütközés alakul ki és explicit szükségünk van rá, hogy megmondjuk, hogy melyik névtér melyik osztályára is gondolunk pontosan. Ebben az esetben a :: operátorral használhatjuk a global kulcsszót a névtér teljes elérésének megadására:
using global::System.IO
Megjegyzés: A global kulcsszó használatára nagyon ritkán lesz szükségünk névtér megadáskor, mivel a legtöbb esetben enélkül is fel lehet oldani a névtereket. Szintén ugyanilyen ritkán fogunk találkozni a :: operátorral is, mivel csak a global kulcsszó esetén engedélyezett a használata.
Névütközések
A névterek remek eszközök, de mi van akkor, ha a kódunkban két különbözÅ‘ névtérben megvalósÃtott, de azonos nevű osztályt is használnunk kell? Ebben az esetben az egyik megoldás, hogy a tÃpus nevét teljes névtér elérési úttal specifikáljuk. Ez a megoldás jól használható addig, amÃg maximum 1-2 alkalommal kell példányosÃtanunk az osztályt a forrásfájlunkon belül.
Azonban ha többször kell, akkor jó lenne valami álnévvel, aliassal illetni a tÃpust. A using kulcsszó erre is alkalmazható.
Például:
using PointDto = MyProject.Dto.Point;
using PointViewModel = MyProject.ViewModels.Point;
A using után szereplÅ‘ név az alias név lesz, amivel tudunk hivatkozni a tÃpusra. Az egyenlÅ‘ségjel után pedig a tÃpus teljes nevének névtérrel együtt kell állnia. C# 12-tÅ‘l kezdÅ‘dÅ‘en a using ezen formában bármilyen tÃpusra alkalmazható. Például Ë™using point = (int x, int y);
A using kiegészÃthetÅ‘ a static kulcsszóval is, amivel statikus osztályokat tudunk használatba venni. Ez azért jó, mert Ãgy megspórolhatjuk az osztály nevének a kiÃrását. Például:
using static System.Console;
class Program
{
static void Main()
{
WriteLine("Static using");
}
}
A program kimenete:
Static using