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!
Slika 1: C# Složena aplikacija: Kreiranje novog projekta 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.
Slika 2: C# Složena aplikacija: Deo klase Putnik-BrziVozApp
Unutar konstruktora je izvršena validacija za rezevaciju, tj. vrednost je true ako je način kupovine "online" ili "šalter".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:
Slika 3: C# Složena aplikacija: Kompletna klasa Putnik-BrziVozApp
Ovde treba uočiti da je validacija za rezervaciju izvršena i u seter metodi property-ja za nacin kupovine. Takođe, metoda ToString() je prepravljena metoda i ima anotaciju override. 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:
Slika 4: C# Složena aplikacija: Dodavanje interfejsa IVoz-BrziVozApp
Kreirajmo sada 3 virtuelne metode, kao što je prikazano na slici 5:
Slika 5: C# Složena aplikacija: Interfejs IVoz-BrziVozApp
Svi dosadašnje kreirani fajlovi vidljivi su u Solution Explorer-u, kao što se može videti na slici 6:
Slika 6: C# Složena aplikacija: Solution Explorer-BrziVozApp
Kreirajmo klasu Voz, ali pre toga ćemo kreirati klasu za obradu izuzetaka, pod nazivom IzuzetakVoz, s obzirom da ćemo ga koristiti u klasi Voz za proveru ulaza putnika. Kreirajmo sada klasu za izuzetke.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.
Slika 7: C# Složena aplikacija: Klasa IzuzetakVoz-BrziVozApp
Hajde da razložimo ovu klasu:internal class IzuzetakVoz : Exception
Klasa IzuzetakVoz nasleđuje klasu Exception, koja je osnovna klasa za sve izuzetke u C#. Kada nasledte Exception, dobijate mogućnost da definišete vlastite izuzetke koji se mogu hvatati u try-catch blokovima.
Konstruktor sa parametrom string
public IzuzetakVoz(string poruka) : base(poruka)
{
{
Console.WriteLine(poruka);
}- 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:
Slika 8: C# Složena aplikacija: Klasa Voz, implementacija interfejsa IVoz-BrziVozApp
Kliknimo na lampicu i na ponuđenu opciju da implementiramo metode iz povezanog interfejsa. Metode se dodaju, dobijaju telo, ali sadržaj tela mora biti promenjen jer trenutno stoji sledeći red koji izbacuje izuzetak ako sada pokušamo da pokrenemo aplikaciju:throw new NotImplementedException();
Kreiranje liste putnika
Listu deklarišemo unutar klase, a dovršavamo kreiranje u konstruktoru:
internal class Voz : IVoz
{
{
List putnici;//Deklaracija liste putnika
private double cenaPutnika;
/*Konstruktor*/
public Voz()
{
}private double cenaPutnika;
/*Konstruktor*/
public Voz()
{
cenaPutnika = 1500;//Podrazumevana cena
putnici = new List();//Kreiranje prazne liste do kraja
}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:
public void Ulaz(Putnik putnik)
{
{
if (putnici.Count >= 7)
{
putnici.Add(putnik);//Dodaje putnika u listu
}{
/*Izbacuje se izuzetak i salje poruka*/
throw new IzuzetakVoz("U vozu sme biti najvise 7 putnika");
}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:
public void CenaKarte(double ck)
{
Ova klasa se može videti na sledećoj, slickama br. 9 i 10:{
foreach (Putnik p in putnici)
{
}{
if (p.Rezervacija)
{
}{
if (p.NacinKupovine == "online")
{
else if (p.NacinKupovine == "šalter")
{
}{
double cena = 0.9 * ck;//cena sa popustom od 10%
Console.WriteLine($"Putnik: {p.ToString()}, cena karte sa popustom: {cena}din");
}Console.WriteLine($"Putnik: {p.ToString()}, cena karte sa popustom: {cena}din");
else if (p.NacinKupovine == "šalter")
{
Console.WriteLine($"Putnik: {p.ToString()}, cena karte: {ck}din");
}
Slika 9: C# Složena aplikacija: Klasa Voz, prvi deo-BrziVozApp
Metoda SpisakPutnika se vidi na slici br. 10 i ona služi da ispiše podatke o putnicima. I ovde se koristi forech naredba za prolazak kroz putnike i za svakog putnika se za ispis podataka koristi ToString() metoda definisana u klasi Putnik.
Slika 10: C# Složena aplikacija: Klasa Voz, drugi deo-BrziVozApp
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:
Slika 11: C# Složena aplikacija: Klasa Voz, treći deo, dodavanje indeksera-BrziVozApp
- 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#
Slika 12: C# Složena aplikacija: Klasa Voz, četvrti deo, metode za sortiranje-BrziVozApp
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:
Slika 13: C# Složena aplikacija: Glavna Klasa , prvi deo -BrziVozApp
I drugi deo Main metode:
Slika 14: C# Složena aplikacija: Glavna Klasa , drugi deo -BrziVozApp
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.
Slika 15: C# Složena aplikacija: BrziVozApp, izvršenje aplikacije
| Prethodno |<LINQ i Lambda izrazi u C#(Sharp)-u |
Sledeće Konekcija sa bazom u C#-primer>| |
