Programozzunk C#-ban – 6. rész
A 6. része a sorozatnak egy viszonylag nagyobb alkalmazás elkészítésével foglalkozik. A készített alkalmazás egy pénz címletező program lesz.
A program konzolos, grafikus felülettel nem rendelkezik. A program forráskódja a következő:
using System; using System.Collections.Generic; namespace _14_cimletezo { /// <summary> /// Kiegészítő függvények /// </summary> static class Kiegeszitok { /// <summary> /// Szótár objektumhoz fűz hozzá egy elemet. Ha az elem létezik a megadott kulccsal, akkor értéket cserél /// </summary> /// <typeparam name="TKey">A kulcs típusa</typeparam> /// <typeparam name="TValue">Az érték típusa</typeparam> /// <param name="dictionary">A szótár</param> /// <param name="key">A kulcs</param> /// <param name="value">Az érték</param> public static void AddEditItem<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey key, TValue value) { if (dictionary.ContainsKey(key)) dictionary[key] = value; else dictionary.Add(key, value); } } class Program { /// <summary> /// Kerekítés szabályainak megfelelően kerekíti a bemeneti összeget /// </summary> /// <param name="bemenet">Bemeneti összeg</param> /// <returns>Kerekített kimenet</returns> private static long kerekit(long bemenet) { long kimenet = bemenet; long maradek = bemenet % 10; if (maradek >= 8) kimenet += (10 - maradek); else if (maradek >= 6 && maradek <= 7) kimenet -= (maradek - 5); else if (maradek >= 3 && maradek <= 4) kimenet += (5 - maradek); else if (maradek >= 1 && maradek <= 2) kimenet -= maradek; return kimenet; } /// <summary> /// A megadott összeget címletekre bontja fel /// </summary> /// <param name="osszeg">a felbontandó összeg</param> private static void Cimletez(long osszeg) { long hatravan = osszeg; int[] cimletek = { 20000, 10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5 }; Dictionary<int, long> cimletezett = new Dictionary<int, long>(); foreach (var cimlet in cimletek) { if (hatravan < cimlet) continue; long mennyi = hatravan / cimlet; hatravan -= mennyi * cimlet; cimletezett.AddEditItem(cimlet, mennyi); if (hatravan == 0) break; } Console.WriteLine("Az összeg címletezve:"); foreach (var cimlet in cimletezett) { Console.WriteLine("{0} db {1} Ft-os", cimlet.Value, cimlet.Key); } } static void Main(string[] args) { try { Console.WriteLine("--------------------------------------------------"); Console.WriteLine("Címletező program"); Console.WriteLine("--------------------------------------------------"); Console.Write("Add meg a címletezendő összeget: "); long input = Convert.ToInt64(Console.ReadLine()); input = kerekit(input); Console.WriteLine("A cimletezeshez a kerekitett osszeg: {0}\n", input); Cimletez(input); Console.WriteLine("Nyomj egy gombot a kilepeshez..."); Console.ReadKey(); } catch (Exception ex) { Console.WriteLine("Hiba Történt!"); Console.WriteLine("A hiba leírása: {0}", ex.Message); } } } } |
A program működése
A forráskód csak egy újdonságot tartalmaz. Ez a Kiegeszitok osztály AddEditItem függvénye. Ez egy ún. Extension Method, vagyis kiegészítő metódus. Ráadásul ez a függvény még generikus is. Generikus függvények esetén a függvény neve után <> jelek között vesszővel elválasztva meg kell adni a használt típusokat. A függvény visszatérési értéke természetesen generikus is lehet.
A függvény attól lesz kiegészítő metódus, mert a függvény statikus osztály statikus függvénye és az első paramétere this kulcsszóval van ellátva. A this kulcsszó egyébként egy objektumon belül az objektumra mutat. Azonban ebben a kontextusban (statikus osztály esetén nincs értelme this kulcsszóval mutatni objektumra) azt jelzi a fordítónak, hogy ez egy kiegészítő metódus, amit a this kulcsszóval megadott objektum típushoz rendeljen hozzá.
Így az AddEditItem metódus minden generikus Dictionary osztályon használható. A függvény egyébként azt csinálja, hogy ha a megadott kulcs alapján a szótár nem tartalmaz egy bizonyos elemet, akkor felveszi azt a megadott értékkel. Ha pedig a szótár tartalmazza a kulcsot, akkor meg a kulcs alapján átírja a kulcshoz tartozó értéket.
A kerekit függvény a magyarországi kerekítési szabályoknak megfelelően 5 vagy 0 végződésre kerekíti a számot. Ehhez a bemeneti számot először elosztja maradékosan 10-el. Így a művelet eredményeképpen kapott maradék 0 és 9 közé fog esni. Ez alapján pedig meghatározza a kimeneti kerekített összeget.
A tényleges címletezést a Cimletez függvény végzi. Itt egy tömbben tárolva vannak az elérhető címletek, méghozzá csökkenő sorrendben. A kimeneti eredményeket egy szótár tárolja. Itt a kulcs a címletet jelöli, míg az érték azt, hogy mennyi alkalommal szerepel az összegben az adott címlet.
A címletezési folyamat egy ciklusból áll, ami végigpróbálja az összes lehetséges címletet a beadott pénzösszegen, amit a folyamatban a hatravan változó tárol. Amennyiben a hátralévő, még nem címletezett összeg nagyobb, mint az aktuálisan próbált címlet, akkor a program elosztja a hátralévő részt az aktuális címlettel, majd a kapott szám és a címlet értékét kivonja a hátralévő részből.
Tehát 32000 Ft esetén első futás esetén az összeg nagyobb, mint 20000. Ezért elvégzi a 32000/20000 műveletet. Mivel ezek egész számként vannak tárolva, az osztás eredménye is egész szám lesz, ami 1. Így a 32000-ből levonásra kerül az 1×20000, marad 12000 címletezetlen összeg.
A folyamat közben az 1 és a 20000 tárolódik a szótárban. A ciklus addig ismétlődik, amíg a hátralévő összeg nem 0.
Ha a címletezéssel végzett a program, akkor a szótárban tárolt értékeket formázottan kiírja a képernyőre.
A fő függvényben a program hibavédelemmel ellátott adatbekérést végez. A bekért szám long típusban tárolódik, így 4 milliárd forintnál nagyobb összegek címletezésére is képes a program (nem mintha egy egyszeri földi halandónak szüksége lenne ilyesmire, de nem lehet tudni, hogy milyen gyorsan inflálódik a pénzünk, illetve a statisztikában az az igazán szép, hogy bármilyen kicsi is a dolgok esélye, fel kell készülni az összes lehetőségre 🙂 .)
A cikkhez tartozó példakódok a https://github.com/webmaster442/csharppeldak címen szerezhetőek be.