A C# programozási nyelv

Bevezetés

Előszó

A C# (ejtsd: szí sarp) a Microsoft által kifejlesztett általános célú imperatív programozási nyelv. A nyelv a C++ kifejezőerejét igyekszik ötvözni a Visual Basic egyszerű használatával Javas elemekkel kiegészítve. A szintaktikus alapokat a C++-tól kölcsönzi, míg az egyszerűséget a Visual Basic-től. A C#-ot sokan hasonlítják még a Java-hoz, mint látni fogjuk nem alaptalanul. (Emellett a C#-ra sokan a Microsoft technológiai válaszaként tekintenek, a rivális Sun-nal szemben.) A nyelv támogatja az objektum-elvű programfejlesztést, valamint tartalmazza a C++ programnyelvi eszközeinek jelentős részét és néhány újszerű elemet is. A nyelv a .NET keretrendszer bázisnyelve, kényelmes és gyors lehetőséget biztosít ahhoz, hogy a keretrendszer alá alkalmazásokat készítsünk. A C# és a .NET keretrendszer alapja a Common Language Infrastructure(CLI).

A nyelv jellemzői:

Különbségek a C++ és a C# között

Történet nagyon röviden:

1972 C Dennis Ritchie
1980 C osztályokkal
1983 C++
1989 Standard C
1998 Standard C++
1995 Java
2000 C# .Net1
2005 C# .Net2

Név eredete:

A név eredete egészen érdekes. Mivel sok köze van a nyelvnek a C++-hoz ezért nagyon sokan azt gondolják, hogy a # a két +-jel "egymásbacsúsztatásával" jött létre. Valójában a # a zenei félhangok jelölésére szolgáló kettős kereszt jelet szimbolizálja, mivel ilyen jel nincsen az ASCII karakterkészletben. Mivel a C# C alapokon nyugszik de nem nyújtja azt a szabadságot, mint a C++, ezért valahol a kettő nyelv között fél úton helyezkedik el. A # jel tehát ezt a C-t emeli fél "hanggal" feljebb, pont úgy, mint a C++ ++ operátora anno.

Az első C# programunk:

class Hello
{
static void Main(string[] args)
{
System.Console.WriteLine("HELLO WORD! ");
}
}

Itt az első különbség: A Main-t nagy M-el írjuk!

Forma és jelentés

A C++ és a C# formailag nagyon hasonló, azaz megtartotta a megszokott jelölésrendszert, de a jelentése sok helyen eltér, mivel a C# a biztonságosságot és egyszerű kezelhetőséget a jól átgondoltsággal párosította. Ezért van az, hogy sok helyen a Javahoz is hasonlítják, mert jól bevált ötletekből is merített, de a Java következő verziójában is felfedezhetőek a C# hatásai.

Nincs mutató de van delegált

A legnagyobb különbség a két nyelv között hogy a C#-ban általában nincs mutató. Azért mégis csak van néha, mert a rendszerközeli programozáshoz mégis csak kellenének, ezért nem biztonságos környezetben úgynevezett "unsafe" módban lehet használni.

Eddig az alkalmazások rossz memóriakezelése miatt az operációs rendszernek előbb-utóbb elfogyott a szabad memóriája, és ez csak a rendszer újraindításával volt megoldható. A régebbi programozási nyelvekben, például a C++-nál, a programozó feladata volt, hogy a már nem használt objektumok törlésével felszabadítsa a memóriát. Csakhogy erről sok programozó megfeledkezik.

A .NET keretrendszer más memóriakezelést használ. Itt a CLR utalja ki az alkalmazásoknak a szükséges memóriát, folyamatosan figyelve, hogy az alkalmazás használja-e még azokat vagy sem. Ha nem, törli őket. Lényegében a szemétgyűjtés elvén működő, automatikus memóriakezelésről van szó.

Néha szükség lenne függvényre mutató pointerre, erre a célra találták ki a delegate függvényt. Olyan függvényre mutathat aminek a paraméter és visszatérési érték típusa megegyezik a delegate típusával.

Miért is kell nekünk, mikor jó? Egy jó példa erre, hogy a leszármaztatott osztály hivatkozik egy pontra (ez a delegált), amit meg akar hívni. Az ős osztályban kitalálunk egy hatékonyabb algoritmust. Ekkor csak a "függvény pointer"-t kellene átállítani C++-ban C#-ban meg a delegáltat, hogy a mi új függvényünket hívja meg. És nem kell újra fordítani.

A delegate függvény visszatérési értéke ha void típusú akkor több függvényre is hivatkozhat, mint egy hírlevélre fel lehet rá iratkozni += -vel és -= -vel leiratkozni, ha = -et használunk akkor felülírjuk az eddigi hivatkozásokat.

Különbség a C++ pointere és a delegate függvény között, hogy a delegate formátuma jobban kötött. Míg a pointerrel bárhova lehet C++-ban mutogatni, a C#-ban csak függvényre és adott típusú paraméter és visszatérési értékekre mutathat. Ez azért jó, mert meghíváskor biztosan tudjunk milyen függvényre hivatkozunk, sokkal biztonságosabb és ellenőrizhetőbb kód lesz.

Bővebben

Szemétgyűjtés

A második nagy különbség a szemétgyűjtés a Garbage Collection (továbbiakban GC). Azaz a memóriában lefoglalt területek felszabadításával nem nekünk kell foglalkoznunk, hanem a rendszer maga szabadítja fel valamilyen algoritmus alapján azokat a helyeket, amire már nem fogunk tudni használni, így a memóriaszivárgás elkerülhető. Ez ki van egészítve a memória töredezettség elkerülésére egy tömörítő algoritmussal. Ezért van az, hogy a mutatók használata nem biztonságos. Mivel a memória terület amire mutat a szemétgyűjtés során más helyre kerülhet, míg a mutató ezt nem követi.

Egyszerűbb

A C# nyelvtana egyszerűbb lett a C++ hoz képest, például a struktúrák elérése sok különböző jel (:: . -> ) helyett C#-ban csak a pontot használja.

A fenti példába: System.Console.WriteLine("HELLO WORD! ");

Itt a System.Console névtérnek a WriteLine(..) metódusát a "HELLO WORD! " paraméterrel hívjuk meg. De hasonlóan csak egy pont kell, ha egy osztály adattagját akarjuk elérni.

Névtér

Elérkeztünk a névtérhez. Ez a tulajdonság már a C++-ban is jelen van, de a C#-ban kötelező mindennek névtérben lennie. Ha valahova nem írjuk ki az azt jelenti, hogy névtelen névtérben van. A névterek segítenek az azonos nevű függvények ütközését elkerülni, ha más névtéren belül van. Illetve az azonos névtérben levő függvények és osztályok azonos fordítási egységbe kerülnek. A C#-ban a partial kulcsszó segítségével egy osztály két file-ba is lehet rakni és a fordító egybe fordítja. Ekkor ügyeljünk, hogy azonos névtérben legyenek. Ez például megfigyelhető a Form osztálynál, ahol a design részt, amit összekattintgatunk az egyik file-ban lesz, míg a kód amit írunk egy másik file-ba kerül.

Bővebben

Kiírás

A C++-ban a kiírni a cout illetve cin szavakkal lehet és ezeket a << és >> operátorokkal terhelhetjük túl.

A C#-ról fontos tudni, hogy mindennek van toStrig(..) metódusa Mivel minden az általános Object ős osztályból származik és neki van toStrig(..) metódusa. A metódus formázási karakterekkel paraméterezhető, ahol a típusnak megfelelően mást és mást jelenthet.

Például: ha a vmi szám

s new String = vmi.ToString(”?”); (Convert.ToInt32();)

Formázó karakterek c,d,e,f,n,x,g,r, … (vagy a nagy betűs párjuk) jelentése: pénz, decimális, hatvány alak, fix pontos, számérték, hexadecimális, általános, kerekített…

A String osztály úgynevezett sealed osztály, ami azt jelenti, hogy nem lehet belőle származtatni, csak használni mint kész osztály.

A korábban megismert kiíró metódust kiegészítjük:

Kapcsoszárójelekben megadható a paraméter sorszáma 0-val kezdve a számozást. Mivel mindennek van toString() metódusa így nem lép fel konvertálási probléma.

A másik nagy ötlet, hogy a @ után az idézőjelben megadott szöveg változatlanul íródik ki.

System.Console.WriteLine("Hello! {0}{1}", nev, 2);

System.Console.WriteLine(@"c:\csarp"); c:\csarp

System.Console.WriteLine("c: \\csarp"); c:\csarp

A metódus paraméterei (mint Stringek) vannak kiírási formátumai, amik így is megadhatóak.

Például: Egy lebegőpontos szám:

float fVal = .0000789F;

int i = 1234

System.Console.WriteLine("{0:f}, {0:g}",fVal); Eredmény: 0.00, 7.89E-05

System.Console.WriteLine(" {0:##,###0}", 2000); Eredmény: 2,000

Tervezésnél a többnyelvűség és a kompatibilitás

Az új nyelvekkel kapcsolatos általános elvárások a szemétgyűjtés, kivételkezelés, kód biztonság, bővíthetőség. A C# fejlesztéskor a tervezők törekedtek a biztonságos, modern, egyszerű, objektum központú, tömör nyelv megalkotására.

A .NET keretrendszer kiválóan alkalmas az egymástól elszigetelt rendszerek problémájának megoldására. Így a külön-külön megírt rendszerek integrálása révén bármely eszközről, bármely időpillanatban és formában hozzá lehet férni az adatokhoz. A legfontosabb jellemzők között a közös futtatókörnyezet, a CLR emelhető ki, amely minden .NET nyelvben megírt kódnak egységes futtatási környezetet és nyelvfüggetlenséget biztosít.

A tekintetben is komponensorientált, hogy a többi komponenstechnológiához hasonlóan helytranszparenciát biztosít, ezenkívül az XML segítségével lehetővé teszi az integrációt más rendszerekkel. Lényeges eleme ezenkívül a rendszernek a tervezési technológiák szabványosítása. Így az UML modellezési technológia alkalmazásával az összes üzleti folyamat leírható, és a tervezés végén természetesen egységes .NET kód képződik.

Nagyon fontos tényező a többnyelvűség; ez nem okoz konfliktusokat a különböző programok között, mivel minden fejlesztő ugyanarra a .NET Frameworkre, ugyanarra az osztályszerkezetre épít – ez biztosítja az egységes megvalósulást. E tényező azért nagyon fontos, mert ha másnak kell átvennie egy adott program fejlesztését, akkor az új ember, a régi osztálykönyvtárra építve, más nyelven is folytathatja a munkát.

C# és a .Net adattípus

int System.Int32

long System.Int64

char System.Char

bool System.Boolean ...

referencia (osztály, karakterlánc, interface, tömbök, delegáltak)

érték (alap típusok)

A típusok: Lásd C++

osztálynév obj =new osztálynév();

static adattag - osztálynév.adattag
(obj.-ra hiba!) Class1.s

Property ≈ Get() Set() metódusok

struct - érték

class – referencia

class Class1
{
static public int s;
private int myx;
public int x
{
get{return myx;}
set{myx = value;}
}
}

Tömbök a C#-ban

A tömbök tömbje és a tömbdimenziós tömb is van a C#-ban. Mivel a tömb egyik tulajdonsága a hossza, ezért fordítási időben ellenőrzi a tömbök túlindexelését. (Persze van kivétel, amikor nem ellenőrizhető. Például, ha véletlen számmal generáljuk a tömb méretét, akkor csak futáskor derül ki ha túlindexeljük.)

int[] a; a = new int[2] {1,2};

int[,] t; t = new int[2, 3] {{2,3,4 },{2,4,5}};

int [][] b = new int [10][]; b[0]=new int[]{2,4,6};

System.Console.WriteLine("{0},{1},{2}{3}",

b.Length, b[0].Length,t.GetLength(0), a.Length);

Bővebben a referencia típusoknál

Különbségek az öröklődésnél

A virtuális függvények közti különbség (erre példa az öröklődés fejezetben)

public [new] void f(){..}

public [new] virtual void f(){..}

A [new] nélkül C++ ugyanazt az f ősfüggvényt definiálja felül, ami egyszer virtuális függvény volt az virtuális is marad C++-ban. C#-ban override kulcsszó felüldefiniálja új függvénnyel míg itt a példában az első esetben csak elrejti egy nem virtuális függvénnyel, a második új virtuális függvény listát hoz létre.

A C#-ban az absztrakt osztály egy metódusának lehet törzse. (erre példa az absztrakt osztályok fejezetben)

A .NET Keretrendszer

Bevezetését a világhálón tapasztalható változások indokolták. Az eddig elszigetelt rendszerek helyett az egymással kommunikáló heterogén rendszerekre volt/van igény. A Microsoft átgondolta az eddigi technológiáit, megnézte, melyek azok, amelyek jó irányba indultak el, és melyek azok, amelyeket az évek folyamán addig fejlesztgetett tovább, hogy már nincs értelme tovább bonyolítani, inkább érdemes teljesen az alapoktól, a menetközben megváltozott igényeknek megfelelően a nulláról újra kidolgozni. A keretrendszer világméretekben is példátlan méretű rendszer több mint 4500 osztályával és több mint 50 ezer interfészével. Rendszer egyik célja, hogy a programozó csak az adott feladatra koncentráljon, és ne vesszen el a részletekben. Az egyszerűség abban látszik meg a legjobban, hogy egy XML alapú Web szolgáltatás fejlesztése csupán annyiban tér el egy szokásos szoftver fejlesztésétől, hogy a szolgáltatást nyújtó szoftver metódusait egyszerűen el kell látni az ún. WebMethod attribútummal, a különbségek implementálásáról maga a rendszer gondoskodik automatikusan. Sőt egy WAP alapú vagy SmartPhone-ra esetleg PocketPC-re írt alkalmazásban is körülbelül ennyi eltérés tapasztalható.

Common Type System: Ez a kulcs, hogy egy programot több nyelven is lehessen fejleszteni, a fordítóknak tudják, hogy milyen adattípusokat hozhatnak létre, hogy foglalják le és szabadítsák fel az objektumokat.

Common Language Runtime: olyan rendszer, ami összehozza a különböző nyelven megírt kódokat, menedzseli őket, és szolgáltatásokat nyújt, többek között a típus biztosság ellenőrzését. A fordítók olyan kódot generálnak, amely képes kommunikálni a CLR-el, ezt a kódot hívjuk menedzselt kódnak. Ez a kód tette lehetővé az ún. alkalmazási tartomány (application domain) bevezetését, ami viszont mentesít bennünket attól, hogy az operációs rendszer processz mechanizmusával tudjuk csak megvédeni logikailag független kódjainkat egymástól, így egy processzben nyugodtan lehet akár több száz alkalmazási tartomány.

Menedzselt Komponensek: egy programkód fordítása után a kimenet lehet exe, dll... Ezek nagyon hasonlóak a már megszokott PE (Portable Executable) fájlokhoz, annyi különbséggel, hogy a generált kód nem x86 futtatható kód, és nem platform-optimizlált. Ez egy MSIL ( Microsoft Internal Language), tartalmaznak meta-adatokat és magát a IL-t.

Majd indításkor magában az exe-ben egy 6 bájtos kódrészlet indul el, ami meghív egy importált CLR metódust, ezért szükséges a keretrendszer megléte minden olyan gépen, ahol futtatni szeretnénk .NET alatt írt programot. Ekkor Elindul a JIT (Just-In-Time compiler) majd futtatja a programot, ennek előnye, hogy platformfüggetlen. A koncepció az, hogy csak akkor fordít a JIT, ha szükség van rá, tehát minden objektum kódját első hivatkozásakor.

.NET szerkezete

Többszörös öröklés

A .NET keretrendszer vázlatos szerkezetét mutatja. Legalul van az operációs rendszer, e fölött pedig a Common Language Runtime (CLR) futtatórendszer. Ez az a komponens a keretrendszerből, amelyet nap mint nap használunk, még ha nem is látjuk. A CLR gondoskodik az olyan rendszerszolgáltatásokról, mint az osztálybetöltés, a fordítás, a kivételkezelés, a memóriakezelés, a biztonság stb. Lényegében lehetővé teszi a .NET alatti programvégrehajtást. A CLR futtatórendszer felett új osztálykönyvtárak vannak, legalul az alapkönyvtárral, amely olyan közönséges funkciókat nyújt, mint az állomány I/O-, a karakterlánc-, a TCP/IP-kezelés stb.

A keretrendszer része az ADO .NET, a korábbi ADO-tól alapvetően különböző, teljesen újratervezett adat-hozzáférési rendszer, amely az XML webszolgáltatásokat is támogatja. Itt található egy teljes XML szolgáltatási rendszer az XML parser-től kezdve a szabványos XML DOM alapú dokumentummodellen keresztül egészen az X-PATH-ig és más, felső szintű XML szabványokig terjedő összetevőkkel.

A keretrendszer a kiszolgáló- és az ügyféloldalakon némileg eltér egymástól. A kiszolgálóoldalon van a Microsoft alkalmazáskiszolgálója, az ASP.NET és a Web Forms, amely az ASP.NET űrlapokon alapuló programozási modellje. Támogatja a webszolgáltatásokat és a Mobil Internet Toolkitet is. Ezzel kezelhetők a mobileszközök. A kliensoldalon a Windows Forms az, ami a Visual Basic megszokott űrlapos rendszere, és az MFC evolúciója révén mindkét modellből a legjobb tulajdonságokat örökíti át.