NAPREDNI C#(SHARP) PRIMER
U ovom članku je pokazano, kako se kreira složenog primera u C#, konzolne aplikacije, koja prikazuje tehnike objektno-orijentisanog programiranja, klase, objekte, kolekcije, algoritme sortiranja, interfejse, obradu izuzetaka. Takođe je pokazana i upotrba LINQ upita, kao i Lambda izraza. Posmatrajmo sledeći primer:Primer: Upravljanje putnicima u vozu
Zadatak je da se kreira program koji upravlja putnicima u vozu. Putnik treba da ima informacije kao što su ime, prezime, i način kupovine karte. Potrebno je da se rezervacija automatski potvrdi ako je karta kupljena online ili na šalteru.
Program treba da omogući unos putnika u voz, ali voz može primiti najviše sedam putnika. Takođe, treba omogućiti prikaz svih putnika u vozu, kao i prikaz putnika zajedno sa cenom karte. Cena karte može biti umanjena ako je karta kupljena online, uz određeni popust(npr. 10%).
Dodatno, potrebno je implementirati funkcionalnost za sortiranje putnika po imenu ili prezimenu i prikaz rezultata.
Program treba da omogući i rukovanje greškama koje mogu nastati, na primer, prilikom pokušaja dodavanja više putnika od dozvoljenog u voz(u ovom primeru je 7).
Napomena: Možete koristiti generičke kolekcije za čuvanje podataka o putnicima.
Sličan primer (zadatak br. 8: Upravljanje porudžbinama u restoranu)možete naći na web strani: Dodatni primeri za vezbu - Klase i objekti
Kreiranje novog projekta i instaliranje potrebnih dodatnih paketa
Otvorimo Visual Studio, a zatim kreirajmo Konzolnu aplikaciju pod nazivom BrziVozApp!
Opis primera:
Prvo ćemo kreirati klasu Putnik koja opisuje nekog putnika. Od atributa treba staviti ono što je bitno za ovaj zadatak, a to su opšte informacije o putniku, ime i prezime, zatim način kupovine(online ili šalter) i rezervacija, odnosno da li je putnik rezervisao kartu ili nije.Da bi pokazali upotrebu interfejsa i njihovo povezivanje sa određenom klasom, kreiraćemo interfejs IVoz, gde ćemo definisane potrebne virtualne metode, koje će se implementirati u klasi, ili klasama koje budemo povezali sa ovim interfejsom. Definisaćemo u interfejsu 3 virtualne metode:
- Ulaz() koja prihvata objekat klase Putnik za parametar i koja mora proveriti, da broj putnika ne prelazi ograničenje(7).
- CenaKarte() koja za svakog putnika ispisuje cenu karte sa popustom ili bez. Popust se dobija ako se kupi karta onlajn i u ovom primeru iznosi 10%. Kupovinom na šalteru ne dobija se popust, a osnovna cena karte je 1500din.
- SpisakPutnika()-ispisuje putnike koji se nalaze u vozu.
U glavnoj klasi, kreiraćemo instancu voza, kreirati kolekciju putnika, sortirati je obrnutim redosledom kojim su putnici ulazili u voz.
Ovde treba još uraditi sledeće. Ucitati broj putnika. Ispisati putnike, ali voditi računa da, ako je broj preko ograničenja aplikacija izbaci izuzetak, sa porukom da je broj putnika prekoračen i u tom slučaju ispiše samo prvih 7 putnika.
Sortirati putnike, najpre po imenu, a zatim i po prezimenu i sortirati. Ovde se mogu koristiti, Linq upiti, lambda izrazi ili koristiti interfejs ICompare.
Demonstrirati bacanje i hvatanje izuzetaka.
Kreiranje klase Putnik
U okviru postojećeg projekta dodajmo novu klasu Putnik u fajlu Putnik.cs i implementirajmo je.Ako niste sigurni kako se dodaje nova klasa, pogledajte to u članku: Kreiranje jednostavne aplikacije u C#Dodajmo sledeće atribute: ime, prezime, nacinKupovine, tipa string i rezervacija tipa bool. Dodaćemo i konstruktor sa parametrima u kojem treba uključiti sve parametre sem rezervacije, jel će ona biti programski određena.
Klasa treba da izgleda kao na slici broj 2.
Dalje treba dodati osobine(Property engl.) za sva polja klase i metodu toString() koja je zadužena za ispis podataka: Kompletna klasa je prikazana na slici broj 3:
Analiza ToString() metode. Ona vraća red teksta sa podacima.
Taj red koristi C# string interpolaciju za formatiranje stringova. Evo šta se dešava u svakom delu:
- $: Ovo označava da je string interpoliran. U C#-u, kada koristite $ pre stringa, možete direktno umetati promenljive i izraze unutar {} u string.
- {ime}: Umetanje vrednosti promenljive ime u string. Ovo će biti zamenjeno sa stvarnom vrednošću promenljive ime.
- {prezime}: Slično kao i ime, ovo umetanje će biti zamenjeno sa vrednošću promenljive prezime.
- {nacinKupovine}: Ovaj deo umetne vrednost promenljive nacinKupovine u string.
- {(rezervacija ? "Potvrđena" : "Nije potvrđena")}: Ovo je terner (ternary) operator. Terneri operatori su skraćeni oblik if-else izraza.
- rezervacija: Ovo je uslov. Ako je rezervacija true, onda se koristi "Potvrđena".
- "Potvrđena": Ovo je vrednost koja će biti ubačena u string ako je uslov true.
- "Nije potvrđena": Ovo je vrednost koja će biti ubačena u string ako je uslov false.
Implementacija interfejsa IVoz
Kreirajmo nov interfejs pod nazivom IVoz, kao što je pokazano na sledećoj slici. Desnim klikom u Solution Explorer-u sa desne strane, kliknimo na naziv projekta, pa na Add-> NewItem i prikazaće se dijalog (Add New Item), treba odabrati Interface iz liste i kliknuti na Add dugme, vidi sliku 3:
Kreiranje klase za obradu izuzetaka(IzuzetakVoz)
IzuzetakVoz (vidi sliku 7.) je klasa koja nasleđuje klasu Exception. Ovo znači da je IzuzetakVoz prilagođeni (custom) izuzetak, koji se može koristiti za signaliziranje specifičnih problema u aplikaciji.
Konstruktor sa parametrom string
{
- Konstruktor: Konstruktor klase IzuzetakVoz prima jedan parametar poruka tipa string. Ova poruka predstavlja opis greške ili situacije koja je dovela do izuzetka.
- Poziv bazne klase: : base(poruka) poziva konstruktor osnovne klase (Exception) i prosleđuje mu poruku. Na taj način, kada se izuzetak uhvati u catch bloku, poruka će biti dostupna kroz svojstvo Message izuzetka.
- Console.WriteLine(poruka);: Ova linija koda prikazuje poruku na konzoli odmah nakon što se izuzetak kreira. To je korisno za debugging, ali u pravoj aplikaciji možda nije poželjno da se poruke izuzetaka automatski prikazuju korisnicima na ovaj način.
Implementacija klase Voz i povezivanje sa interfejsom IVoz
Kreirajmo nov fajl Voz.cs, koji će sadržati ovu klasu i napravimo da nasleđuje interfejs IVoz. Program će prijavljivati grešku, sve dok virtuelne metode iz interfejsa ne implementiramo, odnosno dodamo im telo, što se može videti na slici 8:
Kreiranje liste putnika
Listu deklarišemo unutar klase, a dovršavamo kreiranje u konstruktoru:{
private double cenaPutnika;
/*Konstruktor*/
public Voz()
{
putnici = new List
Metoda Ulaz
Metoda Ulaz(Putnik p) treba da doda, poslatog(kao parametar), putnika(objekat klase Putnik), u listu. Prvo se proverava da li je broj putnika u listi premašio ograničenje i ako jeste baca se izuzetak i ovde je prilika da se iskoristi prethodno napravljena klasa za obradu izuzetaka. Metoda je prikazana u nastavku:{
{
throw new IzuzetakVoz("U vozu sme biti najvise 7 putnika");
putnici.Add(putnik);//Dodaje putnika u listu
Metoda CenaKarte
Ova metoda svakom od putnika ispisuje cenu karte. Za prolazak kroz listu se koristi foreach naredba, koja u svakom ciklusu uzima sledećeg putnika iz liste i onda za njega proverava da li ima rezervaciju i da li je način plaćanja "online". Ako jeste onda je cena sa popustom od 10%, ako je rezervisano , a način plaćanja na šalteru, onda se prikazuje podrazumevana cena. Metoda je prikazana u nastavku:{
{
{
{
Console.WriteLine($"Putnik: {p.ToString()}, cena karte sa popustom: {cena}din");
else if (p.NacinKupovine == "šalter")
{
Dodavanje Indeksera unutar metode
Indekser u C# omogućava da objekti klase mogu biti indeksirani kao nizovi. To znači da se može pristupiti elementima u klasi koristeći sintaksu sličnu indeksiranju nizova, na primer myObject[index].Implementacija IndekseraIndekser se implementira koristeći ključnu reč this, koja se koristi kao specijalna metoda za indeksiranje. Ovde je primer indeksera u klasi Voz, koja sadrži listu putnika, vidi sliku 11:
- Ključna reč this: U kontekstu indeksera, this predstavlja instancu klase i omogućava da se klasa ponaša kao niz. Parametar index koji se koristi unutar this predstavlja indeksni parametar za pristup elementima u listi.
- Getter: Metoda unutar get vraća objekat sa specifičnim indeksom iz liste. U ovom primeru, ako je indeks validan (unutar opsega liste), vraća se objekat tipa Putnik. Ako nije, baca se izuzetak IndexOutOfRangeException.
- Setter: Metoda unutar set omogućava postavljanje vrednosti na specifičan indeks. Kao i u getteru, prvo se proverava da li je indeks validan.
Metode za sortiranje
Da bi kreirali metodu za sortiranje po imenu koristićemo LINQ upit za filtriranje i lambda izraz.LINQ (Language Integrated Query) je moćan alat u .NET frameworku koji omogućava upit i manipulaciju podacima iz različitih izvora koristeći isti jezik upita, direktno unutar C# (ili drugih .NET jezika). LINQ pojednostavljuje rad sa podacima, bilo da su oni u memoriji, u bazi podataka, u XML dokumentima ili negde drugde.
Lambda izrazi su ključni deo modernih jezika programiranja kao što je C# i omogućavaju da se pišu inline, anonimne funkcije. U suštini, lambda izrazi omogućavaju definisanje metoda bez potrebe za kreiranjem zasebnih metoda ili klasa.
Više o tome možete pročitati na strani: LINK UPITI I LAMBDA IZRAZI U C#
Dodatna pojašnjenja
- private class PrezimeComparer : IComparer<Putnik>: Klasa PrezimeComparer implementira interfejs IComparer<Putnik>, što znači da mora pružiti implementaciju metode Compare za poređenje objekata tipa Putnik.
- public int Compare(Putnik x, Putnik y): Ovo je metoda iz IComparer<Putnik> interfejsa koja se koristi za poređenje dva objekta Putnik. Metoda treba da vrati:
- 0 ako su objekti jednaki.
- < 0 ako je prvi objekat manji od drugog.
- > 0 ako je prvi objekat veći od drugog.
- if (x == null || y == null): Proverava da li su oba objekta null. Ako jesu, baca ArgumentException jer poređenje null objekata nije moguće i nije smisleno.
- return x.Prezime.CompareTo(y.Prezime);: Ako oba objekta nisu null, poredi njihova prezimena koristeći CompareTo metodu stringa. Metoda CompareTo vraća integer koji pokazuje kako se jedan string poredi s drugim.
Glavna klasa
U glavnoj klasi kreiraćemo instancu voza, kreirati kolekciju putnika, sortirati je obrnutim redosledom kojim su putnici ulazili u voz.Potrebno je ucitati broj putnika. Ispisati putnike, ali voditi računa da, ako je broj preko ograničenja aplikacija izbaci izuzetak, sa porukom da je broj putnika prekoračen i u tom slučaju ispiše samo prvih 7 putnika.
Sortirati putnike, najpre po imenu, a zatim i po prezimenu i sortirati. Demonstrirati bacanje i hvatanje izuzetaka.
Pogledajmo sad kako bi trebalo da izgleda glavna klasa na slikama 13 i 14:
Objašnjenje koda u glavnoj klasi
- Inicijalizacija voza i putnika:
- Prvo se kreira instanca klase Voz, koja će predstavljati voz u aplikaciji.
- Zatim se kreira lista putnika, koja se popunjava instancama klase Putnik sa zadatim imenom, prezimenom i načinom kupovine.
- Obrtanje redosleda putnika:
- Lista putnika se sortira u obrnutom redosledu korišćenjem metode Reverse. Ova operacija simulira da su putnici uneli svoje podatke obrnutim redosledom.
- Unos broja putnika:
- Korisnik unosi broj putnika koji će ući u voz. Ova vrednost se čuva u promenljivoj brPutnika.
- Dodavanje putnika u voz:
- Pokušava se uneti broj putnika koji je korisnik uneo u listu putnika u vozu. Ako broj putnika premašuje dozvoljeni maksimum, baca se izuzetak IzuzetakVoz.
- U slučaju izuzetka, program hvata izuzetak i postavlja broj putnika na 7, što je maksimalan broj dozvoljenih putnika, i ispisuje poruku o izuzetku.
- Ispis spiska putnika:
- Prikazuje se spisak putnika koji su u vozu korišćenjem metode SpisakPutnika klase Voz.
- Izračunavanje cene karte:
- Metoda CenaKarte klase Voz koristi se za izračunavanje i prikazivanje cena karata za sve putnike. Putnicima koji su izvršili rezervaciju preko interneta dodeljuje se popust od 10%.
- Ispis putnika sa online rezervacijom:
- Koristeći LINQ upit, filtriraju se i prikazuju putnici koji imaju potvrđenu rezervaciju i način kupovine „online“. Ovi putnici su sortirani po imenu u opadajućem redosledu.
- Sortiranje putnika po prezimenu:
- Koristeći IComparer interfejs, putnici se sortiraju po prezimenu i rezultat se ispisuje korišćenjem metode IspisiSortirajPoPrezimenu klase Voz.
| Prethodno |<LINQ i Lambda izrazi u C#(Sharp)-u |
Sledeće Konekcija sa bazom u C#-primer>| |
