[[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ő.