Visual Basic I. jegyzet Visual Basic I. jegyzet Írta: Csala Péter
Írta: Csala Péter
I. gyakorlat Bevezető Tartalom •
A .NET keretrendszer és a Visual Studio
•
Elemi típusok
•
Tömbök, struktúrák
•
Elágazások, ciklusok
•
Eljárások, függvények
A .NET Keretrendszer és a Visual Studio - .NET története A .NET körülbelül hét éve van köztünk. Vagyis 2000-ben kezdtek el róla nyilvánosan is beszélni. Valójában 1998-ban kezdődtek el a fejlesztést, amikor elhatározták, hogy nem használják tovább a Sun Java technológiát Microsoft-nál, hanem a saját MS J++ terméket fogják felhasználni a .NET projekt alapjaként. Eredetileg a neve sem .NET keretrendszer volt, hanem Common Object Runtime. Végül 2002.01.05.-én megjelent a .NET első verziója, a .NET Framework 1.0 és vele együtt a Visual Studio 2002.
- Mi is az a .NET? A .NET-re ezeregyfajta meghatározás van, hogy mi is valójában, de igazándiból senki se tudja. Ezért csak körülírni szokás. Íme egy rövid ugyanakkor tömör meghatározás: egy gyors alkalmazásfejlesztést (RAD – Rapid Application Development), platformfüggetlenséget és hálózati átlátszóságot támogató szoftverfejlesztői platform. A .NET által támogatott nyelvek az alábbi programozási paradigmákat „használják”: - objektum-orientáltság: lényege, hogy objektumokkal képezed le a világot, ezeknek van állandó belső állapota, és operációi, amiket más objektumok meghívhatnak. - esemény-vezéreltség: az objektumoknak vannak eseményeik, és ezek bekövetkezésekor hajtódnak végre a kódok. Alapjában véve kétfajta esemény van: Változás, Akció. - deklaratív/imperatív programozás: a deklaratív nyelvnél(SQL, ASP.NET) a kóddal meghatározzuk a célt a fordító vagy futtató rendszernek, míg az imperatív nyelvek(C#, Basic, Pascal) esetén inkább úgymond elmagyarázzák, mit kell csinálni a számítógépnek a kívánt cél eléréséhez. - reflexív programozás: futásidőben képes vizsgálni a kód szerkezetét, felépítést és ezt képes akár módosítani is. Ezt, maga a framework támogatja. -… (pl.: komponens-orientált programozás) Ezek (és még egy jó pár) programozási paradigma segítette a .NET fejlesztőit abban, hogy az elvárásaiknak megfeleljen a .NET platform. Az alábbi elvárásokat támasztották a keretrendszerrel szembe: Átjárhatóság a COM és a .NET komponensek között, közös futattó/fordító környezet, nyelv függetlenség, alap osztály könyvtár, egyszerű terjesztés/telepítés, és persze a biztonság, stb.. Több fejlesztői segédeszköz is rendelkezésünkre áll, kifejezetten a .NET platformon történő fejlesztéshez. A legfontosabb a Visual Studio .NET, a Microsoft által nyújtott integrált fejlesztő környezet (IDE – Integrated Development Enviroment).
- Miből épül fel a .NET keretrendszer? Nézzük meg nagy vonalakban, hogyan is épül fel a .NET Framework (alul-fölfelé kell nézni) C# - Basic - J# - C++ Common Language Specification (CLS) ASP.NET – Winforms
Datas (ADO.NET) - XML Base Class Library (Alap osztályok) Common Language Runtime (CLR) És ezt az egészet öleli körül a Visual Studio. Az alábbi ábra ugyanezt szemlélteti, MSDN konferenciák egyik kedvenc diája:
-- .NET Futtatókörnyezet A .NET Framework két legfontosabb része kétség kívül a CLI(Common Language Infrastructure) és a CLR(Common Language Runtime). Nézzük meg mit foglalnak ezek magukba!
-- CLI A Common Language Infrastructure a különböző programozási nyelven írt programok futtatására szolgáló alrendszere a .NET Keretrendszernek. A megjelenése előtt minden nyelvnek saját futtató modulja volt, hogy a lefordított alkalmazás működhessen. A közös futtathatóságot úgy érték el, hogy minden nyelvet egy úgynevezett CIL(Common Intermediate Language) vagy MSIL (Microsoft Intermediate Language) nyelvre fordítanak le. Erről kicsit később. A CLI egy osztálykönyvtárat és egy virtuális gépet használ. Az osztálykönyvtár jelen esetben a Base Class Library, a virtuális gép pedig a CLR a Common Language Runtime. Itt is látható a Java-féle koncepció, hiszen ők is egy virtuális gépet (Java Runtime Enviroment/ Java Virtual Machine) használnak a lefordított java bytecode futtatásához.
-- CLR Először is tekintsük meg az alábbi ábrát, amely azt próbálja reprezentálni, mennyire is összetett a Common Language Runtime.
Ezt a sok-sok mindent, alapjában véve 4 alrendszerre lehet felosztani (a számozás nem a fontossági sorrendre utal!): <1> Common Type System (CTS) – egységes típusrendszer, mely azokat a .NET típusokat definiálja, amelyek alapjai a CLR működésének. Ő garantálja azt, hogy összes implementált nyelv képes legyen futni .NET platform alatt, aminek az alapja a közös típusrendszer. Tehát minden nyelv innen veszi a típusokat, csak más alias-ként hivatkozunk rájuk (pl.: int C# alatt int, Basic alatt Integer). A CTS felölős ezen kívül a típusok átjárhatóságáért (konvertálás). Minden, ami a CTS-ben van: objektum! Így minden a System.Object-ig visszavezethető. <2> Common Language Specification (CLS) – általános szabályokat fogalmaz meg, melyeket a .NET nyelvnek be kell tartaniuk. Ennek köszönhető a nyelvfüggetlenség, így a .NET alkalmazásainkat bármilyen nyelven is írjuk az eredmény elméletben ugyanaz. <3> Just-In-Time Compiler (JIT) - Ez az IL kódról natív kódra fordító rendszer, erről kicsit később. <4> Virtual Execution System (VES) – virtuális futtató rendszer, mely a CIL parancsot végrehajtja, kezeli memóriát, stb. Összességben a CLR az alábbi 3 szolgáltatást nyújtja nekünk: kódellenőrzés (code verification), kódbiztonság (code access security) és hulladékgyűjtés (garbage collection). Ez az alapja a menedzselt kódnak (lejjebb bővebben). Tehát a CLR igazi előnye, hogy a fejlesztésre magára lehet koncentrálni, nem kell platformvagy gép- specifikus kódot írnunk.
- Fordítási modell Ismét kezdjük ábrákkal, egyből 2-vel!
Ahogy az ábrákon is jól látszik, a következő folyamat játszódik le. Először is a forráskódunkból készül mindenféle fordító(csc.exe, vbc.exe, stb.) segítségével egy IL kód, ami bájtkód. Fontos megjegyeznünk, hogy ez még nem gép-specifikus kód. Ezeket úgynevezett szerelvényekbe fordítjuk le, amik vagy dll vagy exe kiterjesztésük. Ez történik fordítási időben. Futásidőben az IL kódunkat odaadjuk a CLR-nek, amely felügyeli a kódot (lentebb bővebben), majd a JIT segítségével natív, gépi-kódra alakítja, amelyet már a rendszer képes végrehajtani.
-- JIT A JIT fordítás, Just In Time Compilation futás idejű fordításként vagy dinamikus fordításként is ismert, amely bájtkód-fordított rendszerek teljesítményének növelésére szolgáló technika. Mint ahogy föntebb is volt a bájtkódot alakítja natív kódra. Ez azért jó, mert így az IL kódunk hordozható és csak futtatáskor vagy telepítéskor fordul gép-specifikus kóddá. Ezt meg lehet fájl vagy függvény alapon tenni: a függvényeket akkor szükséges csak lefordítani, amikor végrehajtásra kerülnek (innen jön a "just-in-time", éppen időben kifejezés). Célja egyértelműen a bájtkód és a natív kód előnyeinek egyesítése. A forráskód feldolgozása, alapvető optimalizálása, fordítási időben történik. A bájtkódról gépi kódra történő fordítás jóval gyorsabb, mint forráskódról. Háromféle JIT fordításról szokás beszélni: - „Econo” JIT, amely optimalizálatlan natív kódot állít elő, így eldobható, újragenerálható. Ezért lehetséges az Edit&Continue, illetve a debug módú kódellenőrzés - „Standarad” JIT, amely optimalizált kódot generál, és verifikálja az IL kódot - Fordítás telepítéskor, amely futás előtt végrehajtódik, de a natív-kódban verzió ellenőrzés van, így vissza tud állni JIT-re, probléma esetén. Előnye egyértelműen a gyorsabb indulás
- Menedzselt kód Jó szokás az ábranézegetés, ne törjük meg sort, íme ismét két folyamat ábra:
A menedzselt kód a .NET-tel együtt jött, így szinte minden más kódot unmanaged code-nak nevezünk. A Fordítási modell-es ábrán látható volt, hogy egyedül csak a C++ képes unmanaged code-ot előállítani, vagyis a fordító képes egyből natív kódot előállítani. A többi nyelv (C#, Basic, J#, stb..) csak menedzselt kódot képes generálni. (szokás még felügyelt, kezelt kódnak is hívni). A felügyelet ugyebár a CLR feladata. A felügyelet két részre tagolódik: van a kódmenedzselés, és van az adatkezelés. A menedzselt kód verifikálva van. Vagyis kötelező a metaadatok megadása (assembly). Szigorú típusellenőrzés van, paramétereknél illetve visszatérési értékeknél is (erősen típusos nyelvek). Ez által megszűnnek az olyan típus hibák, mint az inicializálatlan változók, tömb túl indexelése, ... Illetve megjelenik a kód szintű kivételkezelés (try-catch)! A menedzselt adatnál élettartam felügyelet van, vagyis van memóriakezelés is. Így a feleslegessé vált objektumokat a Garbage Collector összegyűjti és meghívja a destruktorukat. Illetve nem lesznek elfelejtett pointerek sem. A mendezselt kód végrehajtásakor nagyon sok minden automatikusan megtörténik. A megfelelő szerelvények, osztályok beolvasása (assembly loader, class loader), mindenféle jogosultság kezelés (rbs, cas, ip) és végül fordítás natív kódra (jit), verifikálással együtt.
- Visual Studio A Visual Studio egy olyan fejlesztő eszköz, mely a legkülönfélébb alkalmazások (console, windows application, web service, stb.) fejlesztésében nyújt óriási segítséget. A VS nem csak egy szimpla kódszerkesztő alkalmazás, hanem ennél több. Van benne minden, debugoláshoz szükséges eszközök, fordítási eszközök, deployment-hez eszközök, wizardok, adatbázis manipulátor, stb… Éppen csak kávét nem tud még főzni! A Visual Studio 2005 újdonságaival (2003-hoz képest), illetve használatával kapcsolatban az alábbi cikksorozatot ajánlom azoknak, akik még nem túl sok időt töltöttek az IDE megismerésével: http://www.msiskola.hu/aspnet/Article.aspx?CID=11 (6 cikk)
Elemi típusok A .NET-en belül kétfajta típust szoktunk megkülönböztetni az úgynevezett érték, illetve referencia típusokat.
- Érték típus Az érték típusok olyan változok, melyek ténylegesen magukban tárolják az adatokat/értékeket, nem pedig egy memóriabeli címre mutogatnak. Az ilyen típusú változókat a memória egy úgynevezett stack területén tárolják el. Az érték típusok közül háromféle van: Beépített (Built-In), Felhasználó által létrehozott (User-Defined), illetve az Enumerátorok (Enumerator). Mi csak a beépítettekkel foglalkozunk (boolean + az összes szám típus). Létrehozásuk az alábbi szintaktika szerint történik: Dim variable_name As variable_type Vagyis a változónevét és típusát kell csak megszabnunk. Nézzünk egy egyszerű példát, egy egész típusú változóra: Dim x As Integer x = 25
- Referencia típus A legtöbb .NET típus referencia típus. Ezek annyiban térnek el az érték típusoktól, hogy nem tároljuk el magukban a konkrét értékeket, hanem csak egy referenciát (pointer-t) tárolnak el az adott memória részletről. Ennek az előnye, hogy ha egy referencia típusnak értékül adunk egy másikat, akkor csak a referencia adódik át, vagyis nem jön létre egy új példány a memórián belül az adatokkal, hanem mind a két ref. típus ugyanarra a memóriaszeletre mutat! Az értékeket, amikre a pointerek mutogatnak a memória úgynevezett heap területén vannak eltárolva. Tipikus beépített referencia típusok: String, Array, Exception, Object, stb. Felhasználó által létrehozható referencia típus például egy osztály (később bővebben), de a struktúra már nem minden esetben lesz referencia típus!!! Érdekes dolog például az is, hogy egy egész típusú változó az érték típusú, de egy egész típusú tömb már referencia típus lesz. Referencia típusú változónak létrehozásának szintakszisa teljesen megegyezik az érték típusnál látottakkal.
- Konvertálás Sokszor lesz arra szükségünk, hogy bizonyos értékeket kiírjunk a képernyőre. A kiírató utasítások általában csak string vagy char típusú változót hajlandóak kiírni. Ezért az egyik leggyakrabban használt típuskonverziós metódusunk a ToString() lesz, melyet magán a típuson kell meghívnunk. Pl.: Dim x As Integer = 25 Console.WriteLine(x.ToString())
/ez a kód kivételesen működőképes ToString nélkül is, mivel a VB sok típuskonverziót képes végrehajtani a háttérben a tudtunk nélkül! C# esetén kötelező a ToString(), ilyenkor!/ Ennek a visszafele irányba történő megvalósítása a típus TryParse() metódusa, amely stringből képes valamely alap típusba átkonvertálni. Csak VB esetén elérhető, az alábbi pár típus konverziós utasítás: CBool, CStr, CInt, stb. Használatukra egy példa:
Dim y As Double = 1.007 Console.WriteLine(CInt(y))
Ilyenkor a kiírt érték természetesen 1 lesz. Bármilyen alap vagy nem alap típus esetén is használható a fentieken kívül a Convert osztály. Ennek az osztálynak olyan tagfüggvényei vannak, mint pl.: ToInt32, ToBoolean, ToUInt64. -- Boxing vs. UnBoxing Van még egy segédeszközünk a konverzióhoz, ahol az irány alapján különböztettünk meg kétfajta konvertálást. Érték >> Referencia, ezt hívjuk Boxing-nak. Referencia >> Érték, ezt pedig UnBoxing-nak. Az ilyen típusú műveletekhez általában a CType-ot használjuk (ez C# esetén a kasztolásnak felel meg.) Példák: 'Boxing Dim i As Integer = 12 Dim o As Object = CType(i, Object) 'UnBoxing Dim o As Object = 12 Dim i As Object = CType(o, Integer)
Tömbök, Struktúrák - Tömbök A tömb egy olyan változó, mely több változót tartalmaz, más szavakkal egy változólista. Vagyis, egy adott típusú értékből többet is eltárolhatunk egyetlen objektumban. Nézzük egy példát a használatára: Dim telefon_szam(100) As String telefon_szam(10) = "06-1-222-2222"
Sokszor előfordul majd velünk az, hogy csak futási időben derül ki a tömb mérete, ilyenkor dinamikus tömböt kell használnunk. A tömb létrehozásakor nem mondjuk meg a méretet, hanem majd később valahol a kódban megszabjuk a ReDim utasítással. Dim telefon_szam() As String telefon_szam(1) = "06-1-111-1111" ReDim Preserve telefon_szam(30)
A Preverse kulcsszóra most azért volt szükségünk itt, mivel nem szeretnénk, hogy az előtte beállított értékek elvesszenek. Természetesen van lehetőségünk több dimenziós tömbök létrehozására is, ilyenkor a dimenziókat egymástól vesszővel válasszuk el. Dim matrix(10, 100) As Integer matrix(0, 1) = 1
- Struktúrák A struktúrákat egyes nyelvek esetén szokás saját típusnak is nevezni. A struktúra igazi előnye az, hogy egyetlen objektumban eltárolhatunk többféle különböző típusú adatot. Természetesen a struktúrákból is létrehozhatunk tömböket, nézzünk egy példát: Private Structure dolgozo Dim vnev As String Dim knev As String Dim szulett As DateTime Dim fizetes As Integer End Structure Dim dolgozok(100) As dolgozo dolgozok(0).fizetes = 150000
Elágazások, ciklusok - Elágazások Az elágazás egy vezérlési szerkezet, melynek feladat az, hogy egy feltételtől függően más-más kódrészletet hajtson végre, ha teljesül a feltétel, illetve ha nem. Ezt egy if/else utasítás párossal oldjuk meg, íme egy példa: If ( a > b) Then Console.WriteLine("Az a szám a nagyobb.") Else Console.WriteLine("A b szám a nagyobb.") End If
Az elágazásnak egy kibővített verziója a switch/case struktúra, mely használata esetén egyetlen objektumnak a lehetséges értékeit vizsgáljuk és ez alapján hajtatunk végre kódot. Select Case (a_nyolcas_szam) Case 1 To 5 Console.WriteLine("1 és 5 között van") Case 6,7,8,9,10 Console.WriteLine("5 és 10 között van") Case Else Console.WriteLine("A szám nem 1 és 10 között van") End Select
Értelemszerűen a Case Else, akkor teljesül, ha egyetlen másik feltétel se.
- Ciklusok A ciklus egy olyan vezérlési szerkezet, amelyben műveletek lehet többször egymás után megismételni. A ciklusok típus szerinti csoportosításánál vannak az úgynevezett számlálásos, illetve a feltételes ciklusok.
--Számlálásos ciklus Ez egy olyan ciklus, ami egy adott számszor hajtja végre a ciklusmagot. A ciklusmag műveltek halmaza, amelyek csak akkor hajtódnak végre, ha a ciklusba belépünk. Erre a típusra egy jó példa a For ciklus. Nézzünk erre egy példát: Dim i As Integer For i = 0 To 100 Console.WriteLine("Elem" & i) Next
A Step szó segítségével a lépésközt adhatjuk meg, ami lehet akár törtszám, negatív szám is!
--Feltételes ciklus Ez egy olyan ciklus, ami addig hajtódik végre, ameddig ciklusfeltétel teljesül, vagyis a logikai kifejezés értéke meg nem változik! Erre az egyik legjobb példa a While ciklus. Nézzünk egy példát is rá: Dim x As Boolean = False Do While x = False Console.WriteLine("Ez egy örök ciklus") Loop
A feltételes ciklusokat kétféle csoportba lehet sorolni a feltétel helye szerint. Lehetnek elől, illetve hátul tesztelős ciklusok. Ez csak annyit jelent, hogy a feltételt a ciklusmag előtt vagy utána vizsgálja meg. Ideáig ugyebár elől tesztelős ciklusokat láttunk itt, ezért nézzük meg a másik fajtát is. Dim x As Integer x = 0 Do x += 1 Loop While x < 20 Console.WriteLine("Az x utcsó érték: 20!")
A számlálásos illetve feltételes cikluson kívül még van egy úgynevezett foreach ciklus, ami arra szolgál, hogy egy adott halmaz elemein végig iteráljon. Íme egy példa: Dim IntIdArray(20), IntArrayItem As Integer Console.WriteLine("Az IntIdArray tömb elemei: ") For Each IntArrayItem in IntIdArray Console.WriteLine(IntArrayItem & "\r\n") Next
Eljárások, Függvények Alapjában véve kétfajta eljárás különböztethetünk meg: a szubrutint és a függvényt. A szubrutin és a függvény közötti igazi különbség az az, hogy a függvényeknek mindig van valamilyen visszatérési értékük. Mindkettő arra szolgál, hogy valamilyen bemenő adatokkal végezzen el műveleteket, vagy bemenő adatok hiányában:
- fgv. esetén állítson elő új adatokat - sr. esetén hajtsa végre szekvenciálisan a kódsorokat. Nézzük először a szubrutinokat! Az ilyen típusú eljárások nagyon gyakran előfordulnak, pl.: az esemény-orientált programozásnál. Minden eseményhez rendelt kód valójában egy szubrutin. De ezekről később. Most nézzünk a szubrutinokra, majd utána a magyarázatot: Private Sub melyik_a_nagyobb(ByVal x As Integer, ByVal y As Integer) If(x > y) Then Console.WriteLine(x & " a nagyobb!") Else Console.WriteLine(y & " a nagyobb!") End If End Sub
Két bemenő paramétere van ennek a szubrutinnak, melyek mindketten Integer típusúak. Ha referencia típusú paramétert akarunk átadni bármilyen eljárásnak, akkor a ByVal helyett a ByRef-et használjuk. A szubrutint úgy tudjuk meghívni, hogy a nevével hivatkozunk rá, majd az esetleges paramétereket megadjuk. Ha nincs paraméter, akkor elhagyhatóak a zárójelek! melyik_a_nagyobb(5,7)
Most pedig nézzünk egy példát a függvényekre: Private Function melyik_a_nagyobb_II(ByVal x As Integer, ByVal y As Integer) As Integer If(x > y) Then Return x Else Return y End If End Function
Három különbség tűnhet fel nekünk elsőre. A Sub helyett Function van, ez azért van így, hogy tudja a fordító, hogy ez függvény, nem szubrutin (ha elfelejtjük beállítani a visszatérési értéket, akkor már a kódírás közben is jelez a Visual Studio)! A második dolog, az első sor végén lévő As Integer, ami a függvény visszatérési értékének típusát szabja meg. Erre azért van szükség, mert az erősen típusos nyelvek ezt megkövetelik (Basic, C#,…). Végül az utolsó furcsaság: két return kulcsszó is van a kódban. Ez azért van így, mert a függvénynek mindig kell visszatérési érékének lennie. Vagyis ahányféleképpen futhat le a függvényünk, annyi return-nek kell, vagy a legvégére kell egyetlen return! A függvények meghívása teljesen megegyezik a szubrutinok-éval, de jegyezzük azt meg, hogy ahol meghívjuk a fgv-t, oda a visszatérési érték lesz behelyettesítve futásidőben! Console.WriteLine(melyik_a_nagyobb_II(5,7) & " a nagyobb!")
Természetesen jelenesetben mind a két eljárásnak ugyanaz lesz az eredménye!