[[oktatas:programozás:csharp|< CSharp]] ====== CSharp nyelv haladó ====== * **Szerző:** Sallai András * Copyright (c) Sallai András, 2014, 2018 * Licenc: GNU Free Documentation License 1.3 * Web: http://szit.hu ===== Változók ===== A C#-ban a következő típusok találhatók: * értéktípusok * referencia típusok * mutatók ==== Értéktípusok ==== int a = 35; double b = 35.43; ==== Referencia típusok ==== Bármely programozási nyelvet használjuk az elindított program számára memóriát foglalunk le. Ez a memória minden folyamat számára két részre van osztva. Van egy verem terület és egy halom terület. A referencia egy olyan változó, amely valójában csak egy mutató egy objektumra. A C# nyelvben ilyen referenciákat az osztályokból alkotott "változók" valósítják meg. Tegyük fel, hogy van egy Dolgozo nevű osztályunk, és annak van három tagja: nev, kor, fizetes. Létrehozunk belőle egy joska nevű példányt. Amikor leírom Dolgozo joska; akkor a verem területen létre jön egy hivatkozás (referencia), amely majd a tagokra mutat. A tagok (nev, kor, fizetes) a halom területen lesznek tárolva. Dolgozo joska; // Helyet foglalunk a referenciának joska = new Dolgozo(); // Helyet foglalunk az objektumnak * A referencia számára a verem (Stack) területen foglalunk helyet. * Az objektum számára a halom (Heap) területen foglalunk helyet. ==== Mutatók ==== A C# lehetővé teszi a C és Pascal nyelvből jól ismert mutató típusok használatát. A használata azonban nem biztonságos kategóriába tartozik. Nem is lehet csak úgy használni, ha unsafe módosítót használjuk, /unsafe fordítói kapcsolóval együtt. A C# lévén C alapú nyelv, a C nyelv szintaktikája alapján adjuk meg a mutató típusú változót. A mutatóban érték helyett egy címet tárolunk el. Például egy másik változó címét. A C# nyelvben a mutató típusú változó neve elé egy "*" karaktert teszünk deklaráláskor és definiáláskor is. int *p; Ha egy normál változónak a címét le szeretném kérdezni, a változó neve elé tett "&" jel karakterrel jelzem. &a Mindezek fényében értelmes kifejezés a következő: int *p = &a; Az a változó címét átadom a p mutatónak. A p mutató így mindig a tartalmára mutat. Teljes kód: using System; class Program01 { public static unsafe void Main() { int a = 35; int *p = &a; Console.WriteLine(*p); } } A metódust amelyben használjuk a mutatót meg kell jelölni az **unsafe** módosítóval. A fordításhoz szükség van a **/unsafe** kapcsolóra. Vegyük észre, ha a mutató típusú változó által mutatott értéket szeretném kiíratni, akkor "*" karaktert teszünk a mutató típusú változó neve elé. ===== Regex ===== Egyszerű regex: using System.Text.RegularExpressions; //... public bool IsValid(string value) { return Regex.IsMatch(value, @"^[0-9]*$"); } ===== Paraméterátadás ===== Egy metódusban a paramétereket két módon adhatjuk át: * érték szerint * címszerint Ha egy paraméter érték szerint lett átadva, a metódus formális paraméterlistájában szereplő változó változása semmilyen hatással nincs a metódus aktuális paramétereként megadott változóra. Ha a metódus paramétere cím szerint (referenciaként) van átadva, akkor a metódus formális paraméterének változása, hatással van az aktuális paraméterként megadott változóra is. Egy szimplán megírt metódus a C# nyelvben érték szerinti paraméterátadást valósít meg. Ha a paramétert cím szerint (referenciaként) szeretnénk átadni, akkor a ref vagy az out kulcsszót kell a típus elé tenni a metódus formális paraméterében, és az aktuális paraméterként átadott változó elé is, mint az a következő példa is mutatja. using System; class Program01 { static void csinal1(int a) { a = 1; } static void csinal2(ref int a) { a = 2; } static void csinal3(out int a) { a = 3; } static void Main() { int b = 0; csinal1(b); Console.WriteLine(b); csinal2(ref b); Console.WriteLine(b); csinal3(out b); Console.WriteLine(b); } } Figyeljük meg, hogy az aktuális paraméterként mindenhol 0 lesz átadva a függvények. Az csinal1() metódus nem változtatja meg "b" értékét, de csinal2() és a csinal() már igen. Mi a különbség a ref és az out között? Mindkét esetben a paraméter változó értékének megváltoztatása hatással van a hívás helyére. A különbség abban áll, hogy az out esetén a hívás helyén felhasznált változó értékének nem kötelező kezdőértéket adni. using System; class Program01 { static void csinal2(ref int a) { a = 2; } static void csinal3(out int a) { a = 3; } static void Main() { int b = 0; int c; csinal2(ref b); Console.WriteLine(b); csinal3(out c); Console.WriteLine(c); } } A tömb átadása is cím szerint történik: using System; class Program01 { static void csinal(int[] tomb) { tomb[1] = 9; } static void Main() { int[] tomb = {8, 4, 3}; csinal(tomb); Console.WriteLine(tomb[1]); } } Ha objektumot adunk át, az szintén cím szerint történik, mivel az eleve referencia. using System; class Dolgozo { public String nev; public int kor; } class Program01 { static void csinal(Dolgozo dol) { dol.nev = "Mike"; } static void Main() { Dolgozo joska = new Dolgozo(); joska.nev = "Névtelen"; csinal(joska); Console.WriteLine(joska.nev); } } A fenti program kimenet "Mike", mivel felülírtuk a csinal() metódusban. ===== Kilépés a programból ===== Egy program két módon érhet véget. Vagy ez a szándék, vagy valamilyen hiba történt. Ha sikerült elkapni a hibát, akkor mi magunk utasíthatjuk a programot, a kilépésre, saját hibaüzenet generálva. Ugyanakkor minden program visszatér kilépéskor egy számmal. Ha a program hiba nélkül lépett ki, ez a szám 0. Hiba esetén a 0-tól eltérő számmal illik kiléptetni a programot. A szám utalhat a hiba típusára, vagy azonosíthatja is azt. A C# nyelven kilépés: System.Environment.Exit(0); Hol van szerepe a visszatérési értéknek? A program az operációs rendszer egyik környezeti változójába helyezi el a visszatérési értéket. A program futtatása után ez az érték lekérdezhető.