A blokk · Bevezetés, környezet, Git · 3. tananyag
A programod egy szövegfájl — a processzor viszont csak gépi kódot ért. Ez a fejezet arról szól, mi történik a kettő között: megismered a CLR, az IL, a JIT és a GC betűszavakat, és kimondjuk a .NET-világ alaptörvényét: itt minden objektum.
System.Object.A processzor csak gépi kódot hajt végre: az adott processzortípus
saját, számokból álló utasításkészletét. A
Console.WriteLine("Szia!"); sor a gépnek semmit sem jelent —
valamin keresztül le kell fordítani.
Két hagyományos megoldás létezik, és mindkettőnek ára van:
| Megközelítés | Hogyan működik? | Példa | Ár |
|---|---|---|---|
| Fordítás (compile) | a teljes programot előre gépi kódra fordítjuk | C, C++ | gyors futás, de a kész program csak egyféle gépen fut |
| Értelmezés (interpret) | egy program soronként olvassa és hajtja végre | klasszikus Python | bárhol fut, de lassabb |
A .NET (és a Java) egy harmadik utat választott: a kettő kombinációját.
1. lépés — fordításkor: a C#-fordító (Roslyn) a forráskódot nem gépi
kódra, hanem IL-re (Intermediate Language — köztes nyelv) fordítja.
Ez egy .dll fájlba kerül. Az IL még nem kötődik
processzortípushoz — „félkész”, de már gépiesen feldolgozható kód.
2. lépés — futáskor: amikor elindítod a programot, a CLR (Common Language Runtime — közös nyelvi futtatókörnyezet) betölti az IL-kódot, és a JIT-fordító (Just-In-Time — „éppen időben”) az éppen futtatandó részeket az adott gép processzorára fordítja.
Az IL platformfüggetlen: ugyanaz a .dll fut Windowson,
Linuxon, macOS-en — mindenhol a helyi CLR fordítja gépi kódra. Ráadásul a JIT a
tényleges processzort ismeri, így ahhoz igazíthatja a kódot.
A C#-programod futtatásához a célgépen ott kell lennie a .NET futtatókörnyezetnek (runtime). Ezért látod majd telepítéskor külön az „SDK” (fejlesztéshez) és a „Runtime” (csak futtatáshoz) csomagokat — erről az A4 fejezetben lesz szó.
A CLR nem csak JIT-fordít. Futás közben végig ott áll a programod mögött:
| CLR-szolgáltatás | Mit jelent? |
|---|---|
| JIT-fordítás | IL → gépi kód, futás közben, az adott processzorra |
| Memóriakezelés + GC | helyet ad az objektumoknak, és automatikusan felszabadítja, amire már nincs szükség |
| Típusbiztonság | nem engedi, hogy egy string-et számként használj — a hibát elkapja |
| Kivételkezelés | a futási hibák szabályozott jelzése (a K blokkban tanuljuk) |
A GC (Garbage Collector — szemétgyűjtő) a CLR takarítója. C-ben és C++-ban a programozó kézzel kéri és adja vissza a memóriát — és ha elfelejti visszaadni, a program egyre többet fogyaszt (ez a memóriaszivárgás). C#-ban ezt a GC intézi:
Egy étteremben nem a vendég mosogat: eszik, otthagyja a tányért, és a személyzet időnként leszedi az elhagyott asztalokat. A GC a személyzet — nem kell szólni neki, magától jár körbe.
Most, hogy tudjuk, mi fut (IL a CLR-en), kimondhatjuk a .NET-világ alaptörvényét:
A .NET-ben minden típus egyetlen közös ősből, a
System.Object-ből származik.
Az objektumorientált világban minden objektumnak metódusai és tulajdonságai vannak, lehetnek. Látni fogjuk ezt a C#-nál is, hiszen itt tényleg minden objektum, már egy egyszerűnek tűnő adattípus is.
int szam = 42; szam.ToString(); // "42" — a szám szöveggé alakítja magát szam.GetType(); // System.Int32 — megmondja a saját típusát
Az int valójában csak álnév (alias) a
System.Int32 típusra — ahogy a
string a System.String-re.
A rövid nevet gépeljük, de a háttérben mindig a System.…
típus áll.
Attól, hogy minden az Object leszármazottja, még nem
viselkedik minden típus ugyanúgy: van értéktípus (pl.
int) és referenciatípus (pl.
string, saját osztályok), és a különbség a másolásnál
számít majd. Ezt a H blokkban vesszük — most elég annyi: mindkettő az
Object családfájában van.
Az IL-nek van egy szép következménye: nem csak C#-ból lehet IL-t készíteni. A .NET-nek több nyelve van, és mindegyik ugyanarra a CLR-re fordul:
| Nyelv | Stílus | Ki használja? |
|---|---|---|
| C# | objektumorientált, C-szintaxis | a .NET fő nyelve |
| F# | funkcionális | adatelemzés, pénzügyi világ |
| VB.NET | beszédes, Basic-örökség | régebbi vállalati rendszerek |
Mindhárom nyelv ugyanazt a BCL-t (Base Class Library —
alaposztály-könyvtár) használja: a Console, a
Math, a String, a
List és társaik közösek. Amikor a tananyagban
„beépített osztályt” mondunk (I blokk), mindig a BCL-ről beszélünk.
Döntsd el mindegyik feladatról: a C#-fordító, a JIT, a GC vagy a BCL végzi?
| Python | C# (.NET-en) | |
|---|---|---|
| Hol fut? | egy értelmezőn (sorról sorra) | fordítás után a CLR-en |
| Fordítás | futás közben | előre IL-re, futáskor JIT |
| Hibák jelzése | tipikusan futás közben derül ki | a fordító futtatás előtt sokat elkap |
| Típusok | menet közben változhatnak | rögzítettek, a fordító őrzi |
| Memória | automatikus (GC) | automatikus (GC) — ez közös! |
A legnagyobb napi különbség a hibajelzés: C#-ban a program el sem indul, amíg a fordító hibát lát. Ez eleinte szigorúnak tűnik — valójában ajándék: a hibát te látod meg, nem a felhasználó.
A sharplab.io oldalon C#-fordító fut a böngészőben: bal oldalra kódot írsz, jobb oldalon azonnal látod, mi készül belőle.
int a = 5; int b = 3; System.Console.WriteLine(a + b);
// … részlet a generált IL-ből: ldc.i4.5 // betölti az 5-öt ldc.i4.3 // betölti a 3-at add // összeadja őket call void [System.Console]System.Console::WriteLine(int32)
a * b) — figyeld,
hogyan változik az IL (add → mul).⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás
Rajzold le fejből az utat a Program.cs-től a processzorig.
Hol van benne az IL, hol a JIT?
Melyik betűszó mit takar: CLR, IL, JIT, GC, BCL? Írd le mindegyikhez egy mondatban a feladatát is.
Egy munkatársad C++-ban programozik, és azt mondja: „a C# lassú, mert futás közben még fordítgat”. Mit válaszolnál? Említsd meg azt is, mit nyerünk cserébe. (Segítség: platformfüggetlenség, típusbiztonság, GC.)
A sharplab.io-n írd be:
System.Console.WriteLine("C#".Length); — mit ír ki a
program (jobb oldalt válts Run nézetre)? Mit mond ez arról, hogy „minden
objektum”? (Még egy string literálnak is van tulajdonsága!)
Nézz utána: a Java világában mi felel meg az IL-nek és a CLR-nek? (Keresőszavak: bytecode, JVM.) Miben hasonlít a két rendszer, és miben tér el?
Minden kérdésnél egy válasz helyes. A végén pontszámot kapsz.
| Fogalom | Jelentés |
|---|---|
| gépi kód | a processzor saját utasításkészlete — csak ezt tudja végrehajtani |
| fordító (compiler) | program, amely az egyik nyelvű kódból másik nyelvűt készít |
| IL (Intermediate Language) | köztes nyelv: erre fordul a C#-forráskód |
| CLR (Common Language Runtime) | a .NET futtatókörnyezete: betölti, JIT-eli, felügyeli a programot |
| JIT (Just-In-Time) | futás közbeni fordítás IL-ből az adott gép gépi kódjára |
| GC (Garbage Collector) | automatikus memória-felszabadítás: eltakarítja az elérhetetlen objektumokat |
| BCL (Base Class Library) | a .NET beépített osztálykönyvtára (Console, Math, String, List…) |
System.Object | minden .NET-típus közös őse — ezért „minden objektum” |
| runtime (futtatókörnyezet) | az a szoftverréteg, amely a programot futtatja — .NET-programhoz .NET runtime kell |
System.Object leszármazottja —
még az int-nek is vannak metódusai
(ToString, GetType), mert az
int a System.Int32 álneve.