C# alapok I
Az óra célja egy alap nyelvi tudás biztosítása. Feltételezzük, hogy a hallgató teljesítette a Programozás { Alapjai, I, II } kurzusokat, illetve az Alkalmazásfejlesztés I-et, így ismeri a C, C++ és Java nyelveket. Ez lehetővé teszi, hogy az órán ne az alap programozási konstrukciókkal, hanem a C# nyelv tulajdonságaival foglalkozzunk.
Az anyag a Reiter István - C# programozás lépésről lépésre könyv példáit veszi alapul, melyek során az eszköztár bemutatásra kerül.
Típusok¶
Referencia- és értéktípusok¶
Mint ahogy a Java nyelvből már ismerős lehet, a C#-ban is minden típus egy ősosztályból származik.
Jelen esetben ez az ősosztály a System.Object
.
A közös ősosztályon felül viszont megkülönböztetünk érték és referenciatípusokat.
A referenciatípusú objektumok a heapen foglalnak helyet, míg az értéktípusú változók a stacken (kivéve, ha egy referenciatípusú objektum adattagjai).
Ez az információ segíthet megérteni a függvények paraméterátadását.
- értéktípus:
char
,enum
,bool
,struct
,int
,float
,double
, ... (minden beépített numerikus típus) - referenciatípus:
string
, saját és beépített osztályok,delegate
.
Amennyiben egy referenciatípusú változót értékül adunk egy másiknak, akkor nem az értéke másolódik le, hanem a két változó ugyanarra a memóriaterületre (objektumra) mutat. Ily módon az egyik változó módosítása mindkét változón keresztül érezteti hatását.
1 2 3 4 5 |
|
A double another = variable;
sor lefutásrakor a variable
értéke átmásolódik az another
változó memóriaterületére.
Így annak változtatása nincs kihatással a variable
értékére.
1 2 3 4 5 6 7 8 9 10 |
|
A RefType another = rt;
sor lefutásakor az rt
és az another
objektumok ugyanarra a memóriaterületre mutatnak, így az another
változtatása kihatással van az rt
értékére is.
Konstansok¶
A konstansokat két különálló kulcsszóval tudjuk létrehozni: const
és readonly
.
A const
kulcsszó segítségével egy objektum nem módosíthatóvá tehető és ebben az esetben deklaráció és a definíció egyszerre kell megtörténjen.
A readonly
módosítóval ellátott objektumok is módosíthatatlanok, viszont itt a deklaráció és a definíció szétválik, a definíciónak elég a konstruktorban megtörténnie.
1 2 3 4 |
|
Konvenció szerint (nem csak C# esetén) a konstans változókat NAGY BETŰVEL szokás írni, ezzel is jelezve a fejlesztőknek, hogy egy konstanst használ.
1 2 3 4 5 6 7 8 9 10 11 |
|
Egy readonly
változó kaphat úgy értéket, mint a const
, de nem kötelező a deklaráció során értéket adni neki.
A konstruktorban is változtatható, viszont a MagicMethod
fordítási hibát eredményez.
Nullable típusok¶
Egy referenciatípusú változó deklarációja során a keretrendszer automatikusan null
értékkel inicializálja azt (azaz nem mutat memóriaterületre).
Az értéktípusú változók ezzel szemben alapértelmezett értékekre inicializálódnak (pl. int: 0, bool: false), és kézzel sem tudjuk a null
értéket beállítani.
Ahhoz, hogy az értéktípusú változókhoz is hozzá lehessen rendelni a "még nem definiált" jelzőt, a nullable
típusmódosítót kell alkalmazni.
Ez két módon történhet:
1 2 3 4 5 6 7 8 9 10 |
|
A két írási mód csak a szintaxisban különbözik, a háttérben ugyanarra a konstrukcióra fordulnak. Két propertyt érdemes megemlíteni:
Value
: visszaadja a változóban tárolt értéket.HasValue
: visszaadja, hogy a változó tárol-e értéket (bool).
Amennyiben megpróbálnánk kiíri az anotherNullable
értékét még azelőtt, hogy a hármas számot értékül adjuk neki, InvalidOperationException-t kapunk vissza Nullable object must have a value.
üzenettel.
Implicit típusok¶
A nyelv szigorúan típusos, az implicit típusok csak kényelmi szolgáltatásként érthetők el.
A var
kulcsszó használatakor a változó típusát a fordító a jobb oldali kifejezésből fogja "kitalálni".
Konvenció szerint beépített típusoknál nem szokás használni.
1 2 |
|
Az rt
változó RefType
típusú és a kódrészlet teljesen ekvivalens a RefType rt = new RefType();
sorral.
Névtelen típusok¶
Amennyiben egy típus használatához nincs szükségünk a konkrét megnevezésére, akkor használhatóak a névtelen típusok.
1 2 |
|
Osztályok¶
Osztályok a class
kulcsszó segítségével deklarálhatók.
Az öröklődés a C++-hoz hasonlóan class Child : Base
konstrukcióval valósítható meg.
A C++-től eltérően a C# nem támogatja a többszörös öröklődést, így egy osztálynak csak egy őse lehet, viszont több interfészt is implementálhat.
Adattagok láthatósága¶
Módosító | Jelentése az adattagra nézve |
---|---|
public | Az elérés nincs korlátozva. |
protected | Csak a tartalmazó osztályból és leszármazottaiból elérhető. |
private | Csak a tartalmazó osztályból elérhető. |
internal | Csak a tartalmazó assembly -ből elérhető. |
protected internal | Csak a tartalmazó assembly -ből vagy a leszármazott osztályokból elérhető. |
private protected | Csak a tartalmazó osztályból vagy a tartalmazó assembly -n belül leszármazott osztályokból elérhető. |
Az osztályokban létrehozott adattagok alapértelmezett láthatósága private
.
Tulajdonságok¶
A "tulajdonság" (property
) egy speciális adattagja az osztálynak, mely lehetővé teszi privát változók kontrollált hozzáférését.
Első ránézésre adattagok, viszont speciális metódusok legtöbbször publikus láthatósággal ellátva.
A get
kulcssóz használható a változó értékének elkérésére, a set
pedig a beállítására.
Mindkét esetben lehetőség van különböző validációk és számítások elvégzésére mielőtt visszaadnánk (vagy beállítanánk) az értéket.
Szerencsére a property-ket nem kell kézzel írni, a fejlesztőkörnyezet biztosít gyorsbillentyűket a létrehozásukhoz.
prop + TAB + TAB
1 |
|
propfull + TAB + TAB
1 2 3 4 5 6 |
|
Amennyiben az alapértelmezetten felül szükséges további számítás vagy validálás a get
és a set
blokkokban, akkor az a következő módon tehető meg:
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Parciális osztályok¶
A nyelv megengedi az osztályok több részletben definiálását, ezeket parciális (partial
) osztályoknak nevezzük.
Minden részletnél ki kell írni a partial class
-t ugyanazzal a láthatósági módosítóval, különben fordítási hibát eredményez.
Ezek az osztályok főként a WinForms technológiánál kerülnek elő, amikor az osztály egyik részét a fejlesztőkörnyezet generálja (GUI összekattintgatásból generált kód), a másik felét pedig a programozó írja (eseménykezelés).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
|
Interfészek¶
Az interfész magában meghatároz egy függvényhalmazt, melyet az interfészt implementáló osztálynak kell megvalósítania.
A nyelv nem támogatja a többszörös öröklődést, így egy osztálynak csak egy őse lehet, viszont több interfészt is megvalósíthat. Míg az osztályok esetében az alapértelmezett láthatósági módosító private
, az interfészek esetében ez public
.
Tartalmazhat:
- metódusokat
- propertyket
- indexelőket
- eseményeket (következő óra)
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Amennyiben egy osztály több interfészt implementál, akkor vesszővel elválasztva kell felsorolni őket.
Ha több interfész deklarálná a SampleMethod
-ot, akkor az implementációnak expliciten ki kell mondania, hogy melyiket valósítja meg.
1 2 3 4 |
|
Ha az interfészeken kívül az osztály öröklődik egy másik osztályból, akkor az öröklődésnek kell az első helyre kerülnie, majd az interfészlista következik.
A példából látható, hogy az elnevezési konvenció szerint egy I
betű kerül minden interfész neve elé: IInterfaceName
.
Amennyiben az osztály a csak bizonyos interfészek bizonyos metódusait implementálja, úgy nem lehet példányt létrehozni belőle, abstract
-tá kell tenni azt.
Ebben az esetben az abstract
kulcsszóval kell ellátni, illetve a nem implementált metódusokat fel kell tüntetni.
1 2 3 4 5 |
|
Kiterjesztett metódusok¶
Már létező típusokhoz új metódusokat tudunk hozzáadni anélkül, hogy azokat módosítanánk vagy származtatnánk belőlük.
Ezeket extension method
-oknak nevezzük (és maradjunk az angol névnél).
Egy ilyen metódus létrehozásához egy statikus osztály szükséges statikus metódussal.
1 2 3 4 5 6 7 8 9 10 11 |
|
Ami megfigyelhető: public static class ...
osztályban public static TÍPUS ... (this TÍPUS név)
és egy új objektumot ad vissza a new String(...)
által.
Ezután a TÍPUS
típusú változóra hívható paraméter nélkül a függvény.
Metódusok¶
Referencia szerinti paraméterátadás¶
Paraméterek átadása történhet érték és referencia szerint is. Érték szerinti átadás esetében a paraméter lemásolódik és a metódus ezt a másolatot kapja meg (ProgAlap-on volt ilyesmiről szó). A referencia szerinti paraméterátadásnál egy objektumra mutató referencia (szintén ProgAlap - pointer) kerül átadásra, nem történik másolás. Ily módon a függvényen belül történt változások láthatók a függvényhívás után is.
1 2 3 4 5 6 7 8 9 10 11 |
|
Fontos kiemelni, hogy a referenciával kapott objektum (a tényleges memóriaterület) állapotát módosíthatjuk, magát a referenciát nem. Amennyiben a függvényen belül egy új objektumot hozunk létre, azt hozzárendeljük a paraméterhez, ez nem fog látszódni a függvény lefutása után.
1 2 3 4 5 6 7 8 9 10 11 12 |
|
Ha szeretnénk módosítani a referenciatípusú paraméter referenciáját, azt külön jelezni kell a paraméterlistában a ref
módosítóval.
A parciális osztályban bemutatott példa továbbgondolása a következő.
1 2 3 4 5 6 7 8 9 10 11 |
|
Out paraméter¶
Referencia szerinti paraméterátadásnál már inicializált paramétert kell átadnunk.
Lehetőség van inicializálatlan paramétert is átadni az out
kulcsszó segítségével, ami azt jelzi, hogy a függvény a futása során inicializáljz azt (fordítási hiba, ha elmarad).
Erre példa a public static bool TryParse (string s, out int result);
.
A függvény igaz értékkel tér vissza, ha sikerült a szöveget számmá konvertálnia, és a result változóban adja vissza az eredmény számot.
1 2 3 |
|
Alapértelmezett és opcionális paraméterek¶
Függvények paraméterlistájában lehetőség van alapértelmezett értékek megadására. Ezek a paraméterlista végén szerepelnek, és függvényhíváskor nem kötelező ezeket a paramétereket átadni.
1 2 3 4 5 6 7 8 9 10 11 |
|
Amennyiben ki szeretnénk hagyni a "középső" paramétert, akkor meg kell nevezni a megfelelő opcionális paramétert, aminek értéket adunk (különben a példa utolsó sorában 4-et az optionalstr
-nek szeretné értékül adni).
Feladatok¶
Egy számológép alkalmazás írása.
- Új .NET Core konzolalkalmazás
* 5 4
alakban várja az alkalmazás a sorokat a konzolról (string.Split()
)* = { +, -, *, / }
(összeadás, kivonás, szorzás, osztás)- Ha nem jó a formátum, írja ki, hogy "Rossz formátum, helyes pl. + 5 4"
- Egy jó sor után írja ki az eredményt az alkalmazás és várjon újabb inputot amíg az "exit" sor nem érkezik.
A gyakorlati hét végén (szeptember 19) publikálásra kerül egy referenciaalkalmazás.
Hivatkozások¶
Reiter István - C# programozás lépésről lépésre
Access Modifiers (C# Reference)
Reference types (C# Reference)
Constants (C# Programming Guide)
Nullable value types (C# reference)
Implicitly typed local variables (C# Programming Guide)
Partial Classes and Methods (C# Programming Guide)
Properties (C# Programming Guide)
Extension Methods (C# Programming Guide)
Passing Parameters (C# Programming Guide)