Menu
Webmaster442.hu
Informatika mindenkinek
  • Kezdőlap
  • Írások
  • Programjaim
    • µblock-filter
      • LibItunesXmlDb
  • Letölthető írások
    • Helló világ! Helló C#!
    • Programozható elektronikák
      • Változatok és vásárlási információk
      • Fejezetlista
      • Változások listája
    • Mikrovezérlős rendszerfejlesztés C/C++ nyelven I. – PIC mikrovezérlők
    • Mikrovezérlős rendszerfejlesztés C/C++ nyelven II. – Arduino Platform
    • Mikrovezérlős Rendszerfejlesztés C/C++ nyelven melléklet: C/C++ receptek
    • GNUPlot alkalmazási segédlet
  • Információk
    • Jogi információk
    • Hirdetések
    • Önéletrajz
  • Kapcsolat
  • Sajtó / Rólam írták
Close Menu
Programozzunk C#-ban – 3. rész
2014 augusztus 19

Programozzunk C#-ban – 3. rész

Ruzsinszki Gábor C# .net, c#

A mai leckében megismerkedünk a C# típuskészletével, adatok be – és kírásának módjával, valamint a kivételkezelés alapjaival.

Referencia vs érték

A C# egy erősen típusos nyelv, amely rendelkezik dinamikus típusossággal. Ez a mondat elsőre ellentmondásnak tűnhet. Azonban a C# mindkettővel rendelkezik. A dinamikus típusosság a .NET 4.0 újdonsága volt, így ez a funkció csak .NET 4.0-át vagy újabb keretrendszert célzó alkalmazások esetén használható.

Azonban mielőtt még nagyon belemennék a típusokba, érdemes tisztázni, hogy C# esetén kezelési szempontból kétféle típus létezik. Vannak az értéktípusok és a referenciatípusok. Az értéktípusok minden függvény hívás esetén értékként lesznek átadva. Ez azt jelenti, hogy konkrétan nem a változó van átpasszolva a függvénynek, hanem annak az értéke, vagyis hívás előtt másolódik az érték, tehát az adat nagyon rövid ideig 2x van benne a memóriában.

Ennek a viselkedésmódnak egyszerű típusok, mint számok, szövegek esetén van értelme. De nem csak ezen típusok viselkednek így, hanem minden struktúrából származtatott objektum. Az egyszerű típusok egyébként struktúraként vannak megvalósítva a keretrendszerben.

A másik fő típus a referenciatípusok. Ezek lényegében az osztályok. Itt már ténylegesen a változó van átadva, nem történik másolás, csak 1x van jelen az objektum a memóriában. Ez nagy mennyiségű adatok tárolásánál jó, de néha problémát okoz, ha referencia helyett értékre lenne szükségünk. Erre is kitaláltak megoldásokat, de erről majd a felületek kapcsán írok részletesen.

Eddig zavarosnak tűnhet, a dolog, szóval jöjjön egy példakód.

using System;
 
namespace _02_ertekatadas_pelda
{
    class osztaly
    {
        public double ertek;
    }
 
    class Program
    {
        static void ErtekatadoPelda(double ertek)
        {
            ertek = 2.1;
        }
 
        static void ReferenciaPelda(osztaly referencia)
        {
            referencia.ertek = 2.1;
        }
 
        static void Main(string[] args)
        {
            Console.WriteLine("Érték típus példa");
            Console.WriteLine();
 
            double ertek = 3.14;
            Console.WriteLine("Függvény hívás előtt az ertek: {0}", ertek);
            ErtekatadoPelda(ertek);
            Console.WriteLine("Függvény hívás utan az ertek: {0}", ertek);
 
            Console.WriteLine();
            Console.WriteLine("Referencia típus példa");
            Console.WriteLine();
 
            osztaly o = new osztaly();
            o.ertek = 3.14;
            Console.WriteLine("Függvény hívás előtt az ertek: {0}", o.ertek);
            ReferenciaPelda(o);
            Console.WriteLine("Függvény hívás utan az ertek: {0}", o.ertek);
        }
    }
}

using System; namespace _02_ertekatadas_pelda { class osztaly { public double ertek; } class Program { static void ErtekatadoPelda(double ertek) { ertek = 2.1; } static void ReferenciaPelda(osztaly referencia) { referencia.ertek = 2.1; } static void Main(string[] args) { Console.WriteLine("Érték típus példa"); Console.WriteLine(); double ertek = 3.14; Console.WriteLine("Függvény hívás előtt az ertek: {0}", ertek); ErtekatadoPelda(ertek); Console.WriteLine("Függvény hívás utan az ertek: {0}", ertek); Console.WriteLine(); Console.WriteLine("Referencia típus példa"); Console.WriteLine(); osztaly o = new osztaly(); o.ertek = 3.14; Console.WriteLine("Függvény hívás előtt az ertek: {0}", o.ertek); ReferenciaPelda(o); Console.WriteLine("Függvény hívás utan az ertek: {0}", o.ertek); } } }

A program kimenete:

Érték típus példa
 
Függvény hívás előtt az ertek: 3,14
Függvény hívás utan az ertek: 3,14
 
Referencia típus példa
 
Függvény hívás előtt az ertek: 3,14
Függvény hívás utan az ertek: 2,1

Érték típus példa Függvény hívás előtt az ertek: 3,14 Függvény hívás utan az ertek: 3,14 Referencia típus példa Függvény hívás előtt az ertek: 3,14 Függvény hívás utan az ertek: 2,1

A kód lényege az, hogy az érték típusok esetén, ha egy függvény megpróbálja a függvényen belül módosítani a paraméterként kapott értéket, akkor csak a függvényen belül lesz maradandó a változás, a függvényhívás végeztével az eredetileg átadott érték nem módosul, míg a referencia típusoknál igen.

Az értéktípusok is átadhatóak referenciaként, de ehhez módosítani kell a függvény definíciót és a hívást is. Az alábbi példa ezt mutatja be:

using System;
 
namespace _03_ertekatadas_referencia
{
    class Program
    {
        static void ErtekatadoPelda(ref double ertek)
        {
            ertek = 2.1;
        }
 
        static void Main(string[] args)
        {
            Console.WriteLine("Érték típus referenciaként példa");
            Console.WriteLine();
 
            double ertek = 3.14;
            Console.WriteLine("Függvény hívás előtt az ertek: {0}", ertek);
            ErtekatadoPelda(ref ertek);
            Console.WriteLine("Függvény hívás utan az ertek: {0}", ertek);
        }
    }
}

using System; namespace _03_ertekatadas_referencia { class Program { static void ErtekatadoPelda(ref double ertek) { ertek = 2.1; } static void Main(string[] args) { Console.WriteLine("Érték típus referenciaként példa"); Console.WriteLine(); double ertek = 3.14; Console.WriteLine("Függvény hívás előtt az ertek: {0}", ertek); ErtekatadoPelda(ref ertek); Console.WriteLine("Függvény hívás utan az ertek: {0}", ertek); } } }

A módosításban bevezetett kulcsszó a ref. Ennek segítségével az értéktípusok esetén kikényszeríthető a referenciaátadás az érték helyett. A kulcsszót a hívásban és a függvény definíciójában is el kell helyezni.

Típusok

Mivel erősen típusos a nyelv, rengeteg beépített típus van. Ezek a típusok a .NET keretrendszerben vannak megvalósítva struktúraként és minden .NET keretrendszeren futó nyelvből használhatóak. A C# esetén speciális kulcsszavak is be vannak vezetve a típusok jelölésére. Az alábbi táblázat a típusrendszert foglalja össze:

C# adattípus .NET típus Méret byte-ban Alsó határ Felső határ
sbyte System.Sbyte 1 -128 127
byte System.Byte 1 0 255
short System.Int16 2 -32768 32767
ushort System.UInt16 2 0 65535
int System.Int32 4 -2147483648 2147483647
uint System.Uint32 4 0 4294967295
long System.Int64 8 -2^63 2^63 – 1
ulong System.UInt64 8 0 2^64 – 1
char System.Char 2 0 65535
float System.Single 4 1,5 x 10^-45 3.4 x 10^38
double System.Double 8 5.0 x 10^-324 1.7 x 1010 ^ 308
bool System.Boolean 1 false (0) true (1)
decimal System.Decimal 16 1.0 x 10^-26 7.9 x 10^28
string System.String  n karakter esetén (n+1)*2 byte a mérete

A .NET 4.0 óta van még két speciális szám típus. Ezek a System.Numerics névtérben találhatóak meg. A BigInt típus nagy méretű egész számok tárolására képes, 128 bites egész számok segítségével kezelhetőek. A Complex típus pedig komplex számok leírására szolgál.

A var kulcsszó segítségével egy automatikus típusú változót hozhatunk létre. Ez nem dinamikus típus, mivel a fordítás pillanatában eldől a változó típusa. Hasznos, ha olyan osztályokat akarunk példányosítani, amelyeknek kilométer hosszú neve van.

A dynamic típus segítségével egy olyan változót hozhatunk létre, amelynek a típusa futás közben határozódik meg. Ennek segítségével megkapjuk az olyan nyelvek előnyeit, mint a Python, vagy a PHP, de ezért árat kell fizetni. Az ár pedig sebességben mérhető. A dynamic típust használó kódok jóval lassabban fognak futni. Továbbá, ha dynamic típust használunk, akkor le kell mondanunk programozás közben az IntelliSense összes előnyéről. Ezt a típust azért vezették be egyébként, hogy a C# programjainkba beágyazhatóak legyenek dinamikus típusos szkript nyelvek, mint az IronPython és az IronRuby.

A string-eken különféle műveleteket végezhetünk. Egy dolog azonban fontos. Ha n darab szövegen végzünk összefűzést, az így fog működni: összefűzi az első kettőt, beteszi egy új string változóba. Az új kapott változón és a következőn elvégzi a műveletet, közben csinál egy új változót. Ezt ismétli egészen addig, amíg a végére nem jut. Ez, ha n nagy szám, akkor iszonyat nagy kézifék a programban, valamint iszonyat nagy memória zabáló is.

Jobb megoldás, ha sok szövegen kell műveletet végezni, a StringBuilder osztály alkalmazása, amely hasonló funkcionalitással rendelkezik, mint a string osztály, de láncolt listás adattárolást használ, így ha bővítjük, akkor nem keletkeznek ideiglenes string változók a memóriában.

Adatok bekérése, kiírása

C# esetén a konzolról a Console osztály megfelelő függvényei segítségével tudunk adatokat bekérni. A bekért adat lehet egy adott gomb, vagy egy sor szöveg, esetleg egy karakter. A beolvasásra használható függvények:

int Console.Read();

int Console.Read();

Egy karaktert olvas be, de a karaktert int típusban adja vissza, ezért konvertálni kell, ha a tényleges karakterre és nem a kódjára vagyunk kíváncsiak, akkor konvertálni kell.

string Console.ReadLine();

string Console.ReadLine();

Egy sor adatot olvas be. A sor elválasztó karakter az Enter, ami a szövegekben “\n” karakterrel hivatkozható.

ConsoleKeyInfo Console.ReadKey();

ConsoleKeyInfo Console.ReadKey();

Egy gombot olvas be. A gomb adatai a ConsoleKeyInfo osztályban tárolódnak.

A szövegek önmagukban nem sok mindenre jók, viszont lehet őket konvertálni mindenféle adatra. A Convert osztály egy csomó adatkonvertáló függvényt valósít meg, aminek a segítségével könnyen és egyszerűen konvertálhatunk a típusok között.

A C/C++ stílusú adattípus konvertálás is megmaradt, de ezen konvertálási móddal például nem tudunk szöveget közvetlenül más típussá alakítani, illetve ez a fajta konvertálás nem minden esetbe fogja ugyan azt adni, mint a Convert osztály megfelelő függvénye. A Convert osztály függvényei To névvel kezdődnek, ami után egy .NET típusazonosító áll. Ez fejezi ki azt, hogy a függvény adott típusra konvertál.

Az alábbi példa a Convert osztály alkalmazását mutatja be bekért adatok esetén:

using System;
 
namespace _04_adatbekeres_convert
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Bekérés és konvertálás példa");
 
            Console.Write("Írj be egy számot: ");
            string sor =  Console.ReadLine();
 
            Console.Write("Írj be egy lebegőpontos számot: ");
            string sor2 = Console.ReadLine();
 
            Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1);
            Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2);
 
        }
    }
}

using System; namespace _04_adatbekeres_convert { class Program { static void Main(string[] args) { Console.WriteLine("Bekérés és konvertálás példa"); Console.Write("Írj be egy számot: "); string sor = Console.ReadLine(); Console.Write("Írj be egy lebegőpontos számot: "); string sor2 = Console.ReadLine(); Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1); Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2); } } }

Ha változókat szeretnénk kiíratni a szövegünkben, akkor nem kell azzal bajlódnunk, hogy külön Write vagy WriteLine hívással írassuk ki őket. A szövegben, ahol változó tartalmát szeretnénk beilleszteni, ott egyszerűen kapcsos zárójelek között írjunk be egy számot. Ez a szám arra hivatkozik, hogy a szöveg után, a WriteLine függvény melyik paraméterét kell beilleszteni a programnak a kiírásba. A számozás 0-tól kezdődik, mint ahogy a fenti példában látható.

Kivételkezelés

A kivételkezelés egy igen hasznos nyelvi tulajdonság, segítségével felkészíthetjük a programot arra, ha a felhasználó hülyeséget ír be. C esetén is lehet persze hibákat kezelni, de ott a függvény visszatérési értéke egy int típus, ami jelzi a sikerességet, vagy a sikertelenséget, cserébe, ha tényleges értéket akar visszaadni a függvény, akkor szenvedhetünk referenciákkal meg mutatókkal. Valamint, ha több függvényt használunk, amelyek egymástól függenek, akkor minden egyes függvényhívás eredményét if-else párosokkal kell körbevenni, majd ha az egyik már hülyeséget érzékel, akkor megszakítani a folyamatot, átugorni egy másik pontra.

Gyanítom kellően zavaros és érthetetlen ez a megközelítés. Ha így van, ne csodálkozzunk, a C/C++ szoftverek többségében ebből a hülye megközelítésből ered a legtöbb szoftver hiba.

C# esetén típust ad vissza a függvény, ha pedig hiba volt a futás közben, akkor dob egy hibát, amit egy kivételkezelő blokkal elkapunk. Ez a megközelítés C++ esetén már létezik, de ott nem használja egy függvény se a beépített könyvtárból, így nem is igen ismert. Ennek a fő oka az, hogy a kivételkezelés akkor működik jól, ha csak egy adott osztályból származtatott típusokat lehet kivételként dobni és elkapni.

C# esetén ez megvalósított dolog. Az összes kivételeset, amit kezelhetünk, az Exception osztályból származik, amely rendelkezik egy szöveges leírással és egy csomó nyomkövetési információval, amivel megkönnyíthető a kivételkezelés. Ha saját típusú kivételeket szeretnénk dobálni, akkor az Exception osztályból kell származtatnunk a saját osztályunkat, de számos specializált Exception osztály létezik.

A kivételt úgy tudjuk leginkább realizálni, ha az előző példában a bekérésnél szám helyett, mondjuk azt adjuk meg, hogy asdf. Ekkor normál módban futtatva a programunkat kapunk egy semmitmondó Windows hibaüzenetet, miszerint a program elszállt.

hiba

Viszont, ha debug üzemmódban indítjuk el a programunkat (Debug menü -> Start Debugging), és ugyanúgy hibás bemenetet adunk meg, akkor kapunk egy üzenetet, miszerint nem kezeltünk egy kivételt. Jelen esetben a kivétel típusa FormatException, ami akkor dobódik, ha a beviteli adat konvertálás esetén nem megfelelő formátumú.

hiba_debug

Az alábbi kódrészlet azt mutatja be, hogy hogyan lehet kezelni a futás közben fellépő hibákat.

using System;
 
namespace _05_adatbekeres_convert_hibakezelt
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Bekérés és konvertálás példa");
 
            Console.Write("Írj be egy számot: ");
            string sor = Console.ReadLine();
 
            Console.Write("Írj be egy lebegőpontos számot: ");
            string sor2 = Console.ReadLine();
 
            try
            {
                Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1);
                Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2);
            }
            catch (Exception)
            {
                Console.WriteLine("Hiba történt!! Nem megfelelő a bevitt adat.");
            }
 
        }
    }
}

using System; namespace _05_adatbekeres_convert_hibakezelt { class Program { static void Main(string[] args) { Console.WriteLine("Bekérés és konvertálás példa"); Console.Write("Írj be egy számot: "); string sor = Console.ReadLine(); Console.Write("Írj be egy lebegőpontos számot: "); string sor2 = Console.ReadLine(); try { Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1); Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2); } catch (Exception) { Console.WriteLine("Hiba történt!! Nem megfelelő a bevitt adat."); } } } }

A try blokkban lévő kód az, ami konkrétan kivél védett. A try blokk utáni catch rész határozza meg, hogy milyen hibákat akarunk elkapni. Egy catch blokk csak egy típust kaphat el, de egy try blokk után több catch blokk is jöhet a különböző hibák elkapására és kezelésére. Jelen esetben a blokk mindenféle hibát elkap, mivel Exception típus van beírva és ebből a típusból származik az összes hiba.

Ha a zárójelben (Exception valami) állna, akkor a valami nevű változón keresztül információkat tudnánk kiírni a hiba típusáról a felhasználónak.

A try blokk után állhat egy finally blokk is. Ez olyan kódot határoz meg, amely a kivételkezelés sikeressége és sikertelensége esetén is lefusson. Ide tehetők például a blokkban használt osztályok erőforrás felszabadító utasításai. Az alábbi példa részlet a kiegészített kivételkezelést mutatja be:

try
{
    Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1);
    Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2);
}
catch (Exception ex)
{
    Console.WriteLine("Hiba történt!! Nem megfelelő a bevitt adat.");
    Console.WriteLine("A hiba leirasa: {0}", ex.Message);
}
finally
{
    Console.WriteLine("töltöttkáposzta");
}

try { Console.WriteLine("A bekért szám +1: {0}", Convert.ToInt32(sor) + 1); Console.WriteLine("A bekért lebegőpontos szám osztva 2-vel: {0}", Convert.ToDouble(sor2) / 2); } catch (Exception ex) { Console.WriteLine("Hiba történt!! Nem megfelelő a bevitt adat."); Console.WriteLine("A hiba leirasa: {0}", ex.Message); } finally { Console.WriteLine("töltöttkáposzta"); }

Példák helye

A sorozat példakódjai a https://github.com/webmaster442/csharppeldak címről tölthetőek le

© 2021C# Tutorial.hu
Felhasználó:
Az egyik összeesküvés elmélet margójára Adatok kódolása

Related Posts

C# Tutorial

C#, Könyv hírek

C# Tutorial

Programozzunk C#-ban 8. rész

C#

Programozzunk C#-ban 8. rész

Programozzunk C#-ban – 7. rész

C#

Programozzunk C#-ban – 7. rész

Bejelentkezés & regisztráció

Regisztáció
Bejelentkezés

Közösségi média

Kategóriák

  • Ajánlók (15)
  • Android (12)
  • Bemutató/Teszt (19)
    • Gyorsteszt (3)
  • Game (43)
    • Konzol (3)
  • Gépház (19)
  • Hack (97)
    • Audio (5)
    • Hardware (18)
      • IOT (8)
    • Internet (15)
    • Mplayer (5)
    • Ubuntu/Linux (16)
    • Video (4)
    • Windows (35)
      • Windows 10 (5)
      • Windows 8 (7)
  • Hogyan működik (39)
    • C# (10)
    • Információbiztonság (10)
  • Kiemelt (18)
  • Könyv hírek (21)
  • Nincs kategorizálva (1)
  • Off (26)
  • Programjaim (13)
    • MCU Tools (1)
  • Retro (2)
  • Telefon (8)

Archívum

Címkék

.net 8 10 ajánló Android Arduino c# Crysis debian Facebook Firefox Game Haladó Információbiztonság Itunes Játék karácsony Kezdő Könyv könyvek Laptop Linux Mass Effect Mass Effect 3 Media Player Classic HC Mikrovezérlő Mplayer NES program RaspberryPi Router Service Pack Seven Symbian szerver Telepítés Teszt Total Commander Ubuntu Virtualizáció Vista Vírus Windows XP Youtube

RSS C# tutorial

  • Mire ügyelj egy programozói gyakornoki állásinterjún?
  • Letöltés mappa rendező program – 3. rész
  • Letöltés mappa rendező program – 2. rész
  • Letöltés mappa rendező program – 1. rész
  • Linux futtatása Windows-on
  • .NET Core telepítése RaspberryPi-re & Távoli hibakeresés
  • Informatika érettségi 2007. Október
Back To Top
Webmaster442.hu
© Webmaster442.hu 2021
Powered by WordPress • Themify WordPress Themes

Legolvasottabbak

  • Windows 7 / XP Dual boot
  • Nexus 7 visszafrissítése Android 4-re
  • Android telefonok PC szinkronizálása
  • Windows 10 automatikus frissítés kikapcsolása
  • Windows telepítése OS X mellé

Recent Comments

  • Avatar of Winter Sándor Winter Sándor: Megtaláltam az AUOptions-t. Windows Registry Editor Versio…
  • Avatar of Ruzsinszki Gábor Ruzsinszki Gábor: OpenWRT-vel talán megoldható, gyári router firmware-ek k…
  • Avatar of Ruzsinszki Gábor Ruzsinszki Gábor: Lehet újdonságként fog hatni a hír, de egy informatikus…
  • Avatar of Barni Barni: Kedves Gábor. Eljutottam addig, hogy a Total Commanderben …
  • Avatar of Patrik Patrik: Szia! Szeretnék kis segítséget kérni. Adott egy hálóz…

További olvasnivalók

  • Hétvégi filmajánló
  • Programozzunk C#-ban – 1. rész
  • Andoid futtatása PC-n
  • Bitlocker meghajtók megnyitása Linux alatt
  • Véletlenszámok generálása