Ta del daje pregled splošnih pojmov, ki so uporabljeni v celotni kodi. Oblikovanje aplikacije v C# temelji na naslednjih osnovnih gradnikih:
ToString() – vrača nizovni opis objektov. Uporabno je za enostaven izpis stanja ali povzetek objekta (npr. stanje vinograda ali lastnosti vina).IOceni, IProdaja). Omogočajo enotno zunanjo obliko (API).get in/ali set metode, da nadzorujemo dostop.Vino za podatke o vinu, ZejniStajerc za branje/pisanje podatkov).Exception)?Izjema predstavlja nenormalno situacijo pri izvajanju kode. Če na primer skušamo odstraniti oceno, ki ne obstaja, ali prodati več steklenic, kot jih imamo na zalogi, se vrže izjema. S tem zagotovimo:
Konstruktor je posebna metoda, ki se izvede takoj ob ustvarjanju novega objekta (z ukazom new Razred()). V konstruktorju nastavimo vse ključne lastnosti, inicializiramo seznamne kolekcije ali pričnemo z privzetimi vrednostmi. Če obstaja več konstruktorjev (preobremenjenih), izberemo ustreznega glede na zagotovljene parametre.
public Vino()
{
Ocene = new List<int>();
// Sistem privzeto inicializira vse druge referenčne tipe na null, vrednostne tipe na 0.
// Tukaj želimo, da je seznam ocen vedno vsaj prazen seznam, ne null.
}
ToString()Metoda ToString() je v C# privzeto na voljo v vseh razredih (deduje se iz object). Če jo "prepišemo" (override), lahko vrnemo poljuben opis objektov, razumljiv tudi neprogramerjem. To uporabimo kjerkoli želimo izpisati povzetek stanja objekta, na primer:
public override string ToString()
{
return $"{Ime} ({LetoTrgatve}) - {SortaGrozdja}, Zaloga: {SteviloSteklenic}, Cena: {CenaNaSteklenico}€";
}
Če želimo npr. izpisati vsebino seznama List<Vino>, lahko povemo:
foreach (var v in seznamVin)
{
Console.WriteLine(v.ToString());
}
Če želimo razviti robustno aplikacijo, upoštevamo naslednje korake:
PrevecSteklenicException); višje plasti aplikacije (npr. UI ali glavni zagon) pa ujamemo in ustrezno izpišemo sporočilo uporabniku.Main in vmesni sloj (I/O): tu se skliče branje/pisanje iz zunanjih virov (datoteke, baza). Prijavimo se na dogodke (subscribe) za uspešno/neuspešno branje/pisanje ter ustrezno poskrbimo za povratno sporočilo uporabniku.V nadaljevanju sledijo konkretni razredi in podrobne razlage z vzorčnimi primeri.
V tem poglavju so razloženi splošni jezikovni koncepti, kot so this, base, dostopnost (public/private), lastnosti (get/set), ključne besede sealed, override, virtual, dedovanje in polimorfizem.
thisKljučna beseda this se uporablja znotraj metode ali konstruktorja, da sklicujemo na trenutno instanco razreda. Omogoča dostop do lastnosti in metod trenutnega objekta. Primer:
public class Primer
{
private string ime;
public Primer(string ime)
{
// this.ime se sklicuje na polje razreda, ime pa na parameter
this.ime = ime;
}
public void Izpisi()
{
Console.WriteLine($"Ime objekta je: {this.ime}");
}
}
baseKljučna beseda base se uporablja znotraj podedovanega razreda, da sklicujemo na člane osnovnega (rodovnega) razreda, kot so konstruktor, lastnosti ali metode, ki smo jih v podrazredu morda prepisali (override). Primer:
public class Oseba
{
public string Ime { get; set; }
public Oseba(string ime)
{
Ime = ime;
}
public virtual void PredstaviSe()
{
Console.WriteLine($"Sem oseba z imenom {Ime}.");
}
}
public class Student : Oseba
{
public int VpisnaStevilka { get; set; }
public Student(string ime, int vpisna)
: base(ime) // kliče konstruktor razreda Oseba(ime)
{
VpisnaStevilka = vpisna;
}
public override void PredstaviSe()
{
// base.PredstaviSe() pokliče izvedbo metode iz razreda Oseba
base.PredstaviSe();
Console.WriteLine($"Sem tudi študent, vpisna številka: {VpisnaStevilka}.");
}
}
public in private)V C# določimo vidnost (accessibility) članov razreda z dostopnimi modifikatorji. Najpogostejši sta public in private:
public: član je dostopen kjerkoli (tudi iz drugih razredov in zvezkov/assemblyjev), dokler imamo referenco nanj.private: član je dostopen samo znotraj istega razreda ali strukture, v katerem je definiran. Ne moremo ga poklicati iz zunaj razreda.Primer omejitev:
public class BankaRacun
{
// To polje je zasebno – lahko dostopamo do njega samo znotraj tega razreda
private double stanje;
// Uporabnik uporablja to javno lastnost (property), da pridobi stanje
public double Stanje
{
get { return stanje; }
private set { stanje = value; }
// set je private – samo znotraj razreda lahko spreminjamo stanje
}
public void DodajPolog(double znesek)
{
if (znesek > 0)
{
Stanje += znesek;
}
}
}
get in set)Namesto javnih polj se v C# uporablja mehanizem lastnosti (properties), ki omogoča nadzor nad brskanjem in nastavljanjem vrednosti. Lastnost vsebuje get in/ali set metode (accessorje), ki se izvedejo, ko poskušamo prebrati ali zapisati vrednost.
public string Ime { get; set; } – avtomatska lastnost, kompilator ustvari skrito polje. get in set sta javna.public int Starost { get; private set; } – lastnost, ki jo lahko preberemo javno, a nastavimo samo znotraj razreda (set je private).
private int letoRojstva;
public int Starost
{
get
{
return DateTime.Now.Year - letoRojstva;
}
private set
{
// Če želimo, da se lastnost Starost nastavi le, ko se ustvari objekt
letoRojstva = DateTime.Now.Year - value;
}
}
virtual, override in sealedvirtual: označi metodo ali lastnost v osnovnem razredu, ki jo lahko podedovani razred prepiše (override).
override: uporabi se v podrazredu, da nadgradi izvedbo metode ali lastnosti, ki je bila v osnovnem razredu označena kot virtual ali abstract.
sealed: onemogoči nadaljnje prepisovanje metode ali dedovanje razreda. Če označimo metodo kot sealed override, podaran razred ne more te metode več prepisovati. Če označimo razred kot sealed, ga ni mogoče podedovati.
public class Zival
{
public virtual void NarediZvok()
{
Console.WriteLine("Žival izdaja zvok.");
}
}
public class Pes : Zival
{
public sealed override void NarediZvok()
{
Console.WriteLine("Hov hov!");
}
}
// Ta poskus bi povzročil napako, ker je Pes razred končan (sealed) pri metodi NarediZvok
public class Nemscina : Pes
{
public override void NarediZvok()
{
Console.WriteLine("Nemški ovčar laja drugače."); // napaka: ni dovoljeno prepisovanje
}
}
Dedovanje je mehanizem, s katerim en razred (podrazred ali izpeljan razred) podeduje lastnosti in metode drugega razreda (osnovnega ali nadrazreda). Podrazred lahko razširi, ponovno uporabi ali prepiše člane osnovnega razreda.
public class Vozilo
{
public int Hitrost { get; set; }
public void Pospesi(int kmh)
{
Hitrost += kmh;
}
}
public class Avto : Vozilo
{
public string Model { get; set; }
public void Predstavi()
{
Console.WriteLine($"Model: {Model}, Hitrost: {Hitrost}");
}
}
// Uporaba:
Avto mojAvto = new Avto();
mojAvto.Model = "Toyota";
mojAvto.Pospesi(50); // metoda iz osnovnega razreda
mojAvto.Predstavi(); // izpiše: Model: Toyota, Hitrost: 50
Polimorfizem omogoča obravnavanje objektov različnih razredov, ki izhajajo iz istega osnovnega razreda ali vmesnika, z eno samo referenco. Pri tem se izvede pravi (dinamični) tip metode ob zagonu.
public class Oblika
{
public virtual void Risanje()
{
Console.WriteLine("Risanje oblike (splošno).");
}
}
public class Krog : Oblika
{
public override void Risanje()
{
Console.WriteLine("Risanje kroga.");
}
}
public class Pravokotnik : Oblika
{
public override void Risanje()
{
Console.WriteLine("Risanje pravokotnika.");
}
}
// Polimorfizem v akciji:
List oblike = new List
{
new Krog(),
new Pravokotnik(),
new Oblika()
};
foreach (var o in oblike)
{
o.Risanje();
// Če je tip Krog, izvede Krog.Risanje()
// Če je tip Pravokotnik, izvede Pravokotnik.Risanje()
// Drugače izvede Oblika.Risanje()
}
Takšen način omogoči, da ena koda obravnava različne izvedbe istih metod, odvisno od dejanskega tipa objekta, ki se hrani v spremenljivki osnovnega tipa.
V tem razdelku najprej razložimo, kaj pomenijo izjeme in vmesniki, nato pa podrobno predstavimo posamezne razrede/vmesnike.
Exceptions)?Izjeme so mehanizem za obvladovanje napak in nepredvidenih okoliščin med izvajanjem aplikacije. V C# so vse izjeme razredi, ki dedujejo iz System.Exception. Ko se zgodi izjemno stanje (npr. uporabnik je vnesel neveljaven parameter, poskuša prodati preveč steklenic), koda vrže (throw) specifično izjemo. V klicnem bloku (try { … } catch { … }) jo lahko ujamemo in ustrezno obravnavamo:
try
{
var znesek = mojeVino.Prodaj(100); // poskus prodaje 100 steklenic
}
catch (PrevecSteklenicException ex)
{
Console.WriteLine($"Napaka pri prodaji: {ex.Message}");
}
catch (Exception ex)
{
Console.WriteLine($"Nepričakovana napaka: {ex.Message}");
}
Poglejmo sedaj razrede, ki so uporabljeni kot izjeme.
Interfaces)?Vmesnik (interface) v C# je način, da definiramo "pogodbo" – seznam javnih metod (in/ali lastnosti), ki jih mora razred, ki implementira ta vmesnik, izpolniti. Primerjava:
new Razred()).Prednost uporabe vmesnikov:
IOceni vinoKotIOceni = new Vino(…);).Zdaj si oglejmo konkretne razrede/vmesnike.
PrevecSteklenicExceptionTa izjema se vrže, kadar poskušamo prodati več steklenic, kot jih objekt vsebuje. Deduje iz Exception.
public class PrevecSteklenicException : Exception
{
public PrevecSteklenicException(string message)
: base(message)
{
// Klic osnovnega konstruktorja z opisom napake.
}
}
Izjema se običajno vrže v metodi Prodaj(int kolicinaSteklenic) razreda Vino:
public double Prodaj(int kolicinaSteklenic)
{
if (kolicinaSteklenic > SteviloSteklenic)
throw new PrevecSteklenicException(
$"Ne morete prodati več kot {SteviloSteklenic} steklenic.");
SteviloSteklenic -= kolicinaSteklenic;
return CenaNaSteklenico * kolicinaSteklenic;
}
// Predpostavimo, da imamo 5 steklenic
Vino rdece = new Vino("Rdeče vino", 2020, "Cabernet", 13.5, 5, 20.0, "Polno telo");
try
{
rdece.Prodaj(10); // tukaj je 10 > 5, zato se vrže izjema
}
catch (PrevecSteklenicException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
// Izhod: Napaka: Ne morete prodati več kot 5 steklenic.
}
OcenaNeObstajaExceptionIzjema, ki se vrže, če poskušamo odstraniti oceno z neobstoječim indeksom ali z navedenim ID, ki ne obstaja. Deduje iz Exception.
public class OcenaNeObstajaException : Exception
{
public OcenaNeObstajaException(string message)
: base(message)
{
// Klic osnovnega konstruktorja z opisom napake.
}
}
Razred Vino hrani ocene v List<int> Ocene. Če poskušamo odstraniti oceno, ki ne obstaja, se vrže ta izjema:
public int OdstraniOceno(int idOcene)
{
if (idOcene < 0 || idOcene >= Ocene.Count)
throw new OcenaNeObstajaException(
$"Ocena s podanim indeksom ({idOcene}) ne obstaja.");
Ocene.RemoveAt(idOcene);
return Ocene.Count;
}
Vino belo = new Vino("Belo vino", 2021, "Riesling", 12.0, 10, 15.0, "Sveže in sadno");
// Dodamo eno oceno (indeks 0)
belo.Oceni(5);
// Poskusimo odstraniti oceno z indeksom 3 (ne obstaja)
try
{
belo.OdstraniOceno(3);
}
catch (OcenaNeObstajaException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
// Izhod: Napaka: Ocena s podanim indeksom (3) ne obstaja.
}
IOceniVmesnik za objekte, ki jih je mogoče oceniti. Določa tri metode, ki jih mora implementirati vsak razred, ki želi podpirati ocenjevanje (npr. Vino).
public interface IOceni
{
///
/// Doda oceno (1–5) in vrne novo število ocen.
/// Če je ocena izven 1–5, lahko vrže izjemo.
///
int Oceni(int ocena);
///
/// Odstrani oceno po indeksu (0-bazirano). Vrne novo število ocen.
/// Če ocena ne obstaja, vrže OcenaNeObstajaException.
///
int OdstraniOceno(int idOcene);
///
/// Izračuna končno ceno po popustu (%) za dano količino steklenic.
///
double IzracunajKoncnoCeno(double popust, int kolicinaSteklenic);
}
Razred Vino implementira ta vmesnik:
public class Vino : IOceni, IProdaja
{
// Lastnosti...
public List<int> Ocene { get; set; }
public int Oceni(int ocena)
{
if (ocena < 1 || ocena > 5)
throw new ArgumentOutOfRangeException(nameof(ocena),
"Ocena mora biti med 1 in 5.");
Ocene.Add(ocena);
return Ocene.Count;
}
public int OdstraniOceno(int idOcene)
{
if (idOcene < 0 || idOcene >= Ocene.Count)
throw new OcenaNeObstajaException(
$"Ocena s podanim indeksom ({idOcene}) ne obstaja.");
Ocene.RemoveAt(idOcene);
return Ocene.Count;
}
public double IzracunajKoncnoCeno(double popust, int kolicinaSteklenic)
{
double original = CenaNaSteklenico * kolicinaSteklenic;
return original - (original * popust / 100.0);
}
// Preostale metode (Prodaj, ToString itd.)...
}
IOceni na objektu Vino:
// 1. Dodajanje ocene:
Vino cvekla = new Vino("Cvekla", 2019, "Modra Frankinja", 14.5, 20, 18.0, "Polno črno vino.");
int stevilo = cvekla.Oceni(5); // vrne 1
stevilo = cvekla.Oceni(4); // vrne 2
// 2. Poskus dodajanja neveljavne ocene:
try
{
cvekla.Oceni(6); // 6 ni med 1 in 5
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
}
// 3. Izračun cene s popustom:
double cenaPopust = cvekla.IzracunajKoncnoCeno(10.0, 3);
// original = 18.0 * 3 = 54.0
// popust = 10% → 54.0 - 5.4 = 48.6
IProdajaVmesnik za objekte, ki jih je mogoče prodati. Ponuja štiri preobremenjene metode Prodaj. Razredi, ki implementirajo ta vmesnik (kot Vino), morajo poskrbeti za zmanjšanje zaloge in izračun vrednosti prodaje.
public interface IProdaja
{
///
/// Proda eno steklenico po polni ceni.
///
double Prodaj();
///
/// Proda dano število steklenic po polni ceni.
/// Če kolicina > SteviloSteklenic, vrže PrevecSteklenicException.
///
double Prodaj(int kolicinaSteklenic);
///
/// Proda eno steklenico s podanim popustom (%).
///
double Prodaj(double popust);
///
/// Proda dano število steklenic s podanim popustom (%).
/// Če kolicina > SteviloSteklenic, vrže PrevecSteklenicException.
///
double Prodaj(double popust, int kolicinaSteklenic);
}
Implementacija v razredu Vino:
public class Vino : IOceni, IProdaja
{
// Lastnosti: SteviloSteklenic, CenaNaSteklenico, ...
public double Prodaj()
{
return Prodaj(1, 0.0); // Privzeta preusmeritev
}
public double Prodaj(int kolicinaSteklenic)
{
return Prodaj(kolicinaSteklenic, 0.0);
}
public double Prodaj(double popust)
{
return Prodaj(1, popust);
}
public double Prodaj(double popust, int kolicinaSteklenic)
{
if (kolicinaSteklenic > SteviloSteklenic)
throw new PrevecSteklenicException(
$"Ne morete prodati več kot {SteviloSteklenic} steklenic.");
double cenaEnotna = CenaNaSteklenico * (1 - popust / 100.0);
SteviloSteklenic -= kolicinaSteklenic;
return cenaEnotna * kolicinaSteklenic;
}
// Preostale metode (Oceni, OdstraniOceno, ToString itd.)...
}
IProdaja na objektu Vino:
// Predpostavimo, da imamo 20 steklenic vina z ceno 18 EUR/ste.
Vino cvekla = new Vino("Cvekla", 2019, "Modra Frankinja", 14.5, 20, 18.0, "Polno črno vino.");
// 1. Proda 1 steklenico po polni ceni:
double znesek1 = cvekla.Prodaj();
// zaloga: 20 -> 19, znesek1 = 18.0
// 2. Proda 5 steklenic brez popusta:
double znesek2 = cvekla.Prodaj(5);
// zaloga: 19 -> 14, znesek2 = 5 * 18.0 = 90.0
// 3. Proda 1 steklenico s popustom 15%:
double znesek3 = cvekla.Prodaj(15.0);
// cena enotna = 18.0 * 0.85 = 15.3, zaloga: 14 -> 13
// 4. Proda 3 steklenice s popustom 20%:
double znesek4 = cvekla.Prodaj(20.0, 3);
// original = 18.0 * 3 = 54.0, popust = 20% → 43.2, zaloga: 13 -> 10
// 5. Poskus prodaje več kot je na zalogi:
try
{
cvekla.Prodaj(50); // 50 > 10 trenutno
}
catch (PrevecSteklenicException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
// Izhod: Napaka: Ne morete prodati več kot 10 steklenic.
}
Enumi so seznam vnaprej določenih konstant, ki jih uporabimo, kadar želimo zagotoviti, da vrednost spada le v določen nabor možnosti. To preprečuje napake pri vnašanju nizov ali številk "na pamet".
LegaVinogradaPredstavlja možne lege vinogradov. Uporabimo ga, da ne moremo vnesti napačne lege (npr. "Jugozahodna").
public enum LegaVinograda
{
Juzna,
Vzhodna,
Zahodna,
Severna
}
Kadar ustvarjamo nov objekt Vinograd, navedemo lego iz tega seznama:
Vinograd mojVinograd = new Vinograd("Bukov Vinograd", 2.5, LegaVinograda.Vzhodna);
Console.WriteLine($"Lega vinograda: {mojVinograd.Lega}");
// Izpis: Lega vinograda: Vzhodna
VlogaDelavcaPredstavlja možne vloge delavcev v vinogradništvu. Določa, ali je delavec redno zaposlen ali sezonski.
public enum VlogaDelavca
{
Zaposlen,
Sezonski
}
Primer uporabe pri kreiranju novega delavca:
Delavec janez = new Delavec("Janez", "Novak", "Srednja šola", VlogaDelavca.Sezonski);
Console.WriteLine($"Delavec Janez je vloga: {janez.Vloga}");
// Izpis: Delavec Janez je vloga: Sezonski
VinoRazred Vino predstavlja vino s svojimi ključnimi lastnostmi in omogoča ocenjevanje ter prodajo. Z njim modeliramo entiteto vino v aplikaciji.
Ključne lastnosti razreda Vino:
public string Ime { get; set; } – ime vina.public int LetoTrgatve { get; set; } – leto, ko je bilo grozdje trgano.public string SortaGrozdja { get; set; } – sorta grozdja, iz katere je vino.public double AlkoholnaStopnja { get; set; } – vsebnost alkohola v %.public int SteviloSteklenic { get; set; } – trenutno število razpoložljivih steklenic.public double CenaNaSteklenico { get; set; } – cena ene steklenice (v EUR).public string Opis { get; set; } – poljuben opis vina.public List<int> Ocene { get; set; } – seznam ocen (ocene od 1 do 5), ki jih je uporabnik dodal.public Certifikat Certifikat { get; set; } – certifikat, povezan z vinom.Opomba: Seznam ocen vedno inicializiramo v konstruktorju, da ni null. Tako lahko preprosto kličemo Ocene.Add(ocena). Dodali smo tudi lastnost Certifikat, da lahko sledimo veljavnosti certifikatov.
Razred Vino ima tri konstruktorje:
public Vino()
{
// Privzeti konstruktor
Ocene = new List<int>();
Certifikat = null;
}
public Vino(string ime, int letoTrgatve, string sortaGrozdja, double alkoholnaStopnja,
int steviloSteklenic, double cenaNaSteklenico, string opis)
{
Ime = ime;
LetoTrgatve = letoTrgatve;
SortaGrozdja = sortaGrozdja;
AlkoholnaStopnja = alkoholnaStopnja;
SteviloSteklenic = steviloSteklenic;
CenaNaSteklenico = cenaNaSteklenico;
Opis = opis;
Ocene = new List<int>();
Certifikat = null;
}
public Vino(string ime, int letoTrgatve, string sortaGrozdja, double alkoholnaStopnja,
int steviloSteklenic, double cenaNaSteklenico, string opis, List<int> ocene, Certifikat certifikat)
{
Ime = ime;
LetoTrgatve = letoTrgatve;
SortaGrozdja = sortaGrozdja;
AlkoholnaStopnja = alkoholnaStopnja;
SteviloSteklenic = steviloSteklenic;
CenaNaSteklenico = cenaNaSteklenico;
Opis = opis;
Ocene = ocene ?? new List<int>();
Certifikat = certifikat;
}
Vsak konstruktor poskrbi za:
Ime, LetoTrgatve ipd.).Ocene = new List<int>()), da se ne pojavi null.Certifikat = null ali podanega certifikata.Vino:
// 1. Privzeti konstruktor (popolnoma prazen objekt):
Vino praznoVino = new Vino();
Console.WriteLine(praznoVino.Ocene.Count); // 0
// 2. Konstruktor z osnovnimi parametri (ocene se samodejno nastavi na prazen seznam):
Vino rose = new Vino(
"Rosé Slikar",
2022,
"Pinot Noir",
13.0,
30, // številno steklenic
12.5, // cena na steklenico
"Lahkotno, sadno rosé."
);
Console.WriteLine($"{rose.Ime} ({rose.LetoTrgatve}) → Zaloga: {rose.SteviloSteklenic}");
// 3. Konstruktor z vnaprej navedenimi ocenami in certifikatom:
List<int> oceneSeznam = new List<int> { 5, 4, 3 };
Certifikat cert = new Certifikat(
"DOC",
"Slovenska Vinogradniška Zbornica",
new DateTime(2022, 1, 1),
new DateTime(2024, 12, 31)
);
Vino posebnoVino = new Vino(
"Chardonnay Deluxe",
2021,
"Chardonnay",
14.5,
15,
22.0,
"Polno telo, hrastna zorenje",
oceneSeznam,
cert
);
Console.WriteLine($"Št. ocen: {posebnoVino.Ocene.Count}, Certifikat veljaven do: {posebnoVino.Certifikat.DatumVeljavnosti:dd.MM.yyyy}"); // 3, 31.12.2024
Razred Vino vsebuje naslednje javne metode:
int Oceni(int ocena);
int OdstraniOceno(int idOcene);
double IzracunajKoncnoCeno(double popust, int kolicinaSteklenic);
double Prodaj();
double Prodaj(int kolicinaSteklenic);
double Prodaj(double popust);
double Prodaj(double popust, int kolicinaSteklenic);
override string ToString();
Oceni(int ocena)Ta metoda doda oceno (1–5) v seznam ocen in vrne novo število ocen. Če je ocena zunaj dovoljenega razpona, vrže ArgumentOutOfRangeException.
public int Oceni(int ocena)
{
if (ocena < 1 || ocena > 5)
throw new ArgumentOutOfRangeException(nameof(ocena),
"Ocena mora biti med 1 in 5.");
Ocene.Add(ocena);
return Ocene.Count;
}
Oceni:
Vino cvekla = new Vino("Cvekla", 2019, "Modra Frankinja", 14.5, 20, 18.0, "Polno črno vino.");
int st1 = cvekla.Oceni(5); // vrne 1
int st2 = cvekla.Oceni(4); // vrne 2
try
{
cvekla.Oceni(6); // 6 ni dovoljena ocena
}
catch (ArgumentOutOfRangeException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
}
// Izhod: Napaka: Ocena mora biti med 1 in 5.
OdstraniOceno(int idOcene)Odstrani oceno po indeksu (0-bazirano). Če indeks ne obstaja, vrže OcenaNeObstajaException.
public int OdstraniOceno(int idOcene)
{
if (idOcene < 0 || idOcene >= Ocene.Count)
throw new OcenaNeObstajaException(
$"Ocena s podanim indeksom ({idOcene}) ne obstaja.");
Ocene.RemoveAt(idOcene);
return Ocene.Count;
}
OdstraniOceno:
Vino belo = new Vino("Belo vino", 2021, "Riesling", 12.0, 10, 15.0, "Sveže in sadno");
belo.Oceni(5); // lista ocen: [5]
int st = belo.OdstraniOceno(0); // vrne 0, ker je zdaj lista prazna
try
{
belo.OdstraniOceno(2); // indeks 2 ne obstaja
}
catch (OcenaNeObstajaException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
}
// Izhod: Napaka: Ocena s podanim indeksom (2) ne obstaja.
IzracunajKoncnoCeno(double popust, int kolicinaSteklenic)Izračuna skupno ceno s popustom za dano količino steklenic. Originalna cena = CenaNaSteklenico * kolicinaSteklenic. Popust (%) se odšteje od te vsote.
public double IzracunajKoncnoCeno(double popust, int kolicinaSteklenic)
{
double original = CenaNaSteklenico * kolicinaSteklenic;
return original - (original * popust / 100.0);
}
Vino cvekla = new Vino("Cvekla", 2019, "Modra Frankinja", 14.5, 20, 18.0, "Polno črno vino.");
double cena1 = cvekla.IzracunajKoncnoCeno(10.0, 3);
// 3 * 18.0 = 54.0, 10% popust: 54.0 - 5.4 = 48.6
Console.WriteLine($"Končna cena: {cena1} €"); // Izpis: Končna cena: 48.6 €
Prodaj() in preobremenjene različice Prodaj(...)Metode za prodajo zmanjšujejo zalogo (SteviloSteklenic) in vračajo skupni znesek prodaje. Obstajajo štiri različice:
public double Prodaj() // Proda 1 steklenico brez popusta
public double Prodaj(int kolicinaSteklenic) // Proda podano število brez popusta
public double Prodaj(double popust) // Proda 1 steklenico s popustom (%)
public double Prodaj(double popust, int kolicinaSteklenic) // Proda podano število s popustom (%)
V ozadju vse izvedbe uporabljajo zadnjo različico:
public double Prodaj(double popust, int kolicinaSteklenic)
{
if (kolicinaSteklenic > SteviloSteklenic)
throw new PrevecSteklenicException(
$"Ne morete prodati več kot {SteviloSteklenic} steklenic.");
double cenaEnotna = CenaNaSteklenico * (1 - popust / 100.0);
SteviloSteklenic -= kolicinaSteklenic;
return cenaEnotna * kolicinaSteklenic;
}
Prodaj:
// Imamo 20 steklenic vina po 18 €/ste:
Vino cvekla = new Vino("Cvekla", 2019, "Modra Frankinja", 14.5, 20, 18.0, "Polno črno vino.");
// Proda 1 steklenico po polni ceni:
double z1 = cvekla.Prodaj();
// zaloga: 20 -> 19, z1 = 18.0
// Proda 5 steklenic brez popusta:
double z2 = cvekla.Prodaj(5);
// zaloga: 19 -> 14, z2 = 5 * 18.0 = 90.0
// Proda 1 steklenico s popustom 15%:
double z3 = cvekla.Prodaj(15.0);
// enotna cena = 18 * 0.85 = 15.3, zaloga: 14 -> 13
// Proda 3 steklenice s popustom 20%:
double z4 = cvekla.Prodaj(20.0, 3);
// original = 3 * 18 = 54, popust20% = 43.2, zaloga: 13 -> 10
// Poskus prodaje več kot je na zalogi:
try
{
cvekla.Prodaj(50); // 50 > 10 trenutno
}
catch (PrevecSteklenicException ex)
{
Console.WriteLine($"Napaka: {ex.Message}");
// Izhod: Napaka: Ne morete prodati več kot 10 steklenic.
}
ToString()Metoda ToString() vrne niz, ki opisuje stanje objekta Vino. To je uporabno, kadar želimo povzeti vse ključne informacije v enem nizu:
public override string ToString()
{
return $"{Ime} ({LetoTrgatve}) - Sorta: {SortaGrozdja}, "
+ $"Zaloga: {SteviloSteklenic}, Cena: {CenaNaSteklenico} €, "
+ $"Certifikat veljaven do: {(Certifikat != null ? Certifikat.DatumVeljavnosti.ToString("dd.MM.yyyy") : "Brez certifikata")}";
}
ToString():
Vino rdece = new Vino("Rdeče vino", 2020, "Cabernet", 13.5, 5, 20.0, "Polno telo");
Console.WriteLine(rdece.ToString());
// Izpis: Rdeče vino (2020) - Sorta: Cabernet, Zaloga: 5, Cena: 20 €, Certifikat veljaven do: Brez certifikata
// Če ima certifikat:
Certifikat cert = new Certifikat("DOC", "Slovenska Vinogradniška Zbornica", new DateTime(2020,1,1), new DateTime(2023,12,31));
Vino belo = new Vino("Belo vino", 2019, "Riesling", 12.0, 10, 15.0, "Sveže in sadno", new List<int>(), cert);
Console.WriteLine(belo.ToString());
// Izpis: Belo vino (2019) - Sorta: Riesling, Zaloga: 10, Cena: 15 €, Certifikat veljaven do: 31.12.2023
DelavecRazred Delavec predstavlja vinogradnega delavca z imenom, priimkom, izobrazbo, vlogo, razpoložljivostjo in zneskom, ki ga je delavec zaslužil.
Ključne lastnosti razreda Delavec:
public string Ime { get; set; } – ime delavca.public string Priimek { get; set; } – priimek delavca.public string Izobrazba { get; set; } – opis izobrazbe (npr. "Visoka šola").public VlogaDelavca Vloga { get; set; } – vloga delavca (enum: Zaposlen ali Sezonski).public bool Razpolozljiv { get; set; } – ali je delavec trenutno na voljo (true/false).public double Zasluzi { get; set; } – znesek, ki ga je delavec zaslužil do sedaj (EUR).Opomba: Lastnost Zasluzi se posodablja prek metode DodajZasluzek ali se ponastavi prek metode Izplacaj.
Razred Delavec ima tri konstruktorje:
public Delavec()
{
// Privzeti konstruktor
Razpolozljiv = true;
Zasluzi = 0.0;
}
public Delavec(string ime, string priimek, string izobrazba, VlogaDelavca vloga)
{
Ime = ime;
Priimek = priimek;
Izobrazba = izobrazba;
Vloga = vloga;
Razpolozljiv = true;
Zasluzi = 0.0;
}
public Delavec(Delavec original)
{
Ime = original.Ime;
Priimek = original.Priimek;
Izobrazba = original.Izobrazba;
Vloga = original.Vloga;
Razpolozljiv = original.Razpolozljiv;
Zasluzi = original.Zasluzi;
}
Opomba o konstruktorjih:
Razpolozljiv = true in Zasluzi = 0.0. To zagotovi, da vsak nov delavec začne kot razpoložljiv in z nič zaslužka.Delavec:
// 1. Privzeti konstruktor:
Delavec d1 = new Delavec();
Console.WriteLine($"Razpoložljiv: {d1.Razpolozljiv}, Zasluži: {d1.Zasluzi}");
// Izhod: Razpoložljiv: True, Zasluži: 0
// 2. Konstruktor z argumenti:
Delavec d2 = new Delavec("Ana", "Kraner", "Diplomirani inženir", VlogaDelavca.Zaposlen);
Console.WriteLine($"{d2.Ime} {d2.Priimek}, Izobrazba: {d2.Izobrazba}, Vloga: {d2.Vloga}");
// Izhod: Ana Kraner, Izobrazba: Diplomirani inženir, Vloga: Zaposlen
// 3. Kopirni konstruktor:
Delavec d3 = new Delavec(d2);
Console.WriteLine($"Kopija: {d3.Ime} {d3.Priimek}, Zasluži: {d3.Zasluzi}");
// Izhod: Kopija: Ana Kraner, Zasluži: 0
Razred Delavec vsebuje naslednje javne metode:
void Izplacaj(Delavec d);
void DodajZasluzek(Delavec d, double znesek);
override string ToString();
DodajZasluzek(Delavec d, double znesek)Ta metoda doda znesek k lastnosti d.Zasluzi. Če delavca d ni mogoče najti v kontekstu, se lahko vrže izjema (ni prikazano).
public void DodajZasluzek(Delavec d, double znesek)
{
// Predpostavimo, da smo v razredu Vinogradnistvo
// in iščemo d v seznamu SeznamDelavcev.
d.Zasluzi += znesek;
}
DodajZasluzek:
Delavec toni = new Delavec("Toni", "Zupan", "Srednja šola", VlogaDelavca.Sezonski);
toni.DodajZasluzek(toni, 200.0); // Toni.Zasluzi = 200
Console.WriteLine($"Toni zasluži: {toni.Zasluzi} EUR");
// Izhod: Toni zasluži: 200 EUR
Izplacaj(Delavec d)Izplača delavca d – to pomeni posredovanje celotnega zneska d.Zasluzi in ponastavitev d.Zasluzi = 0. Lahko tudi spremeni d.Razpolozljiv = false, če delavca umaknemo iz razpoložljive baze (odvisno od implementacije).
public void Izplacaj(Delavec d)
{
if (!d.Razpolozljiv)
throw new InvalidOperationException("Delavec ni razpoložljiv za izplačilo.");
double znesek = d.Zasluzi;
// Tukaj bi posredovali znesek na bančni račun ali vplačali izplačilo
d.Zasluzi = 0.0;
d.Razpolozljiv = false;
}
Izplacaj:
Delavec liza = new Delavec("Liza", "Novak", "Diplomiran ekonomist", VlogaDelavca.Zaposlen);
liza.DodajZasluzek(liza, 300.0); // liza.Zasluzi = 300
Console.WriteLine($"Pred izplačilom: {liza.Zasluzi} EUR");
// Izhod: Pred izplačilom: 300 EUR
liza.Izplacaj(liza);
Console.WriteLine($"Po izplačilu: {liza.Zasluzi} EUR, Razpoložljiv: {liza.Razpolozljiv}");
// Izhod: Po izplačilu: 0 EUR, Razpoložljiv: False
ToString()Vrne nizni opis stanja delavca:
public override string ToString()
{
return $"{Ime} {Priimek} - Vloga: {Vloga}, Razpoložljiv: {Razpolozljiv}, Zasluži: {Zasluzi:F2} EUR";
}
ToString():
Delavec eva = new Delavec("Eva", "Kos", "Diplomiran ekonomist", VlogaDelavca.Zaposlen);
eva.DodajZasluzek(eva, 150.0);
Console.WriteLine(eva.ToString());
// Izhod: Eva Kos - Vloga: Zaposlen, Razpoložljiv: True, Zasluži: 150.00 EUR
TrgatevRazred Trgatev modelira dogodek trgatve grozdja: datum, sorta, količino, sladkorno stopnjo in seznam delavcev, ki sodelujejo.
Ključne lastnosti razreda Trgatev:
public DateTime DatumTrgatve { get; set; } – datum, ko poteka trgatev.public string SortaGrozdja { get; set; } – sorta grozdja, ki jo trga.public double KolicinaGrozdjaKg { get; set; } – količina v kilogramih.public double SladkornaStopnja { get; set; } – vsebnost sladkorja (°Brix).public List<Delavec> Udelezenci { get; set; } – seznam delavcev, ki sodelujejo na trgatvi.Opomba: Seznam Udelezenci vedno inicializiramo v konstruktorju kot prazen seznam, da ne pride do null reference.
Razred Trgatev ima štiri konstruktorje:
public Trgatev()
{
Udelezenci = new List<Delavec>();
SladkornaStopnja = 0.0;
}
public Trgatev(DateTime datumTrgatve, string sortaGrozdja, double kolicinaGrozdjaKg)
: this(datumTrgatve, sortaGrozdja, kolicinaGrozdjaKg, 0.0, new List<Delavec>())
{ }
public Trgatev(DateTime datumTrgatve, string sortaGrozdja, double kolicinaGrozdjaKg,
double sladkornaStopnja, List<Delavec> udelezenci)
{
DatumTrgatve = datumTrgatve;
SortaGrozdja = sortaGrozdja;
KolicinaGrozdjaKg = kolicinaGrozdjaKg;
SladkornaStopnja = sladkornaStopnja;
Udelezenci = udelezenci;
}
public Trgatev(Trgatev original)
{
DatumTrgatve = original.DatumTrgatve;
SortaGrozdja = original.SortaGrozdja;
KolicinaGrozdjaKg = original.KolicinaGrozdjaKg;
SladkornaStopnja = original.SladkornaStopnja;
Udelezenci = new List<Delavec>(original.Udelezenci);
}
Opis konstruktorjev:
Udelezenci kot prazen seznam in SladkornaStopnja na 0.0. Uporabno, kadar želimo ustvariti objekt in ga nastaviti postopoma.SladkornaStopnja=0.0, prazni udeleženci).
// 1. Privzeti konstruktor:
Trgatev prazna = new Trgatev();
Console.WriteLine($"Št. sodelujočih: {prazna.Udelezenci.Count}"); // 0
// 2. Konstruktor z osnovnimi parametri:
Trgatev majTrgatev = new Trgatev(
new DateTime(2023, 9, 15),
"Chardonnay",
1200.0 // kg
);
// SladkornaStopnja = 0.0, Udelezenci = prazen seznam
// 3. Konstruktor s polnimi parametri:
List<Delavec> ekipa = new List<Delavec>
{
new Delavec("Bojan", "Kralj", "Visoka šola", VlogaDelavca.Sezonski),
new Delavec("Maja", "Horvat", "Srednja šola", VlogaDelavca.Sezonski)
};
Trgatev polnaTrgatev = new Trgatev(
new DateTime(2024, 10, 1),
"Merlot",
800.0,
22.5, // °Brix
ekipa
);
// Izpis podrobnosti:
Console.WriteLine($"Datum: {polnaTrgatev.DatumTrgatve:dd.MM.yyyy}, Sorta: {polnaTrgatev.SortaGrozdja}, Udeleženci: {polnaTrgatev.Udelezenci.Count}");
// 4. Kopirni konstruktor:
Trgatev kopija = new Trgatev(polnaTrgatev);
Console.WriteLine($"Sladkor: {kopija.SladkornaStopnja} °Brix"); // 22.5
Razred Trgatev vsebuje le eno javno metodo:
public override string ToString();
Metoda ToString() vrne strnjen opis trgatve, vključno z datumom, sorto, količino, sladkorno stopnjo in številom udeležencev.
ToString():
public override string ToString()
{
return $"Trgatev {DatumTrgatve:dd.MM.yyyy}, {SortaGrozdja}, {KolicinaGrozdjaKg} kg, "
+ $"{SladkornaStopnja} °Brix, {Udelezenci.Count} delavcev";
}
// Uporaba:
Console.WriteLine(polnaTrgatev.ToString());
// Izhod: Trgatev 01.10.2024, Merlot, 800 kg, 22.5 °Brix, 2 delavcev
VinogradRazred Vinograd predstavlja fizični vinograd z imenom, površino, sortami grozdja, številom trsov, lego in seznamom trgatev.
Ključne lastnosti razreda Vinograd:
public string ImeVinograda { get; set; } – ime vinograda.public double PovrsinaHa { get; set; } – velikost vinograda v hektarjih (ha).public List<string> SorteGrozdja { get; set; } – seznam sort grozdja, ki jih gojimo.public int SteviloTrsov { get; set; } – dejansko število trsov v vinogradu.public LegaVinograda Lega { get; set; } – lega vinograda (enum: Juzna, Vzhodna, Zahodna, Severna).public List<Trgatev> SeznamTrgatev { get; set; } – seznam trgatev, ki so se v vinogradu izvedle ali so načrtovane.Opomba: Seznama SorteGrozdja in SeznamTrgatev vedno inicializiramo kot novi seznami v konstruktorju, da preprečimo null reference.
Razred Vinograd ima tri konstruktorje:
public Vinograd()
{
SorteGrozdja = new List<string>();
SeznamTrgatev = new List<Trgatev>();
SteviloTrsov = 0;
}
public Vinograd(string imeVinograda, double povrsinaHa, LegaVinograda lega)
: this(imeVinograda, povrsinaHa, new List<string>(), 0, lega, new List<Trgatev>())
{ }
public Vinograd(string imeVinograda, double povrsinaHa, List<string> sorteGrozdja,
int steviloTrsov, LegaVinograda lega, List<Trgatev> seznamTrgatev)
{
ImeVinograda = imeVinograda;
PovrsinaHa = povrsinaHa;
SorteGrozdja = sorteGrozdja;
SteviloTrsov = steviloTrsov;
Lega = lega;
SeznamTrgatev = seznamTrgatev;
}
Opis konstruktorjev:
SorteGrozdja in SeznamTrgatev kot prazna seznama, SteviloTrsov = 0. Primeren za postopno napolnitev podatkov (npr. z UI).Vinograd:
// 1. Privzeti konstruktor:
Vinograd prazenVinograd = new Vinograd();
Console.WriteLine($"Št. sort: {prazenVinograd.SorteGrozdja.Count}, Št. trgatev: {prazenVinograd.SeznamTrgatev.Count}");
// Izhod: Št. sort: 0, Št. trgatev: 0
// 2. Konstruktor z ime, površina, lega:
Vinograd apelVinograd = new Vinograd("Apel Vinograd", 1.2, LegaVinograda.Juzna);
Console.WriteLine($"{apelVinograd.ImeVinograda}, Površina: {apelVinograd.PovrsinaHa} ha, Lega: {apelVinograd.Lega}");
// Izhod: Apel Vinograd, Površina: 1.2 ha, Lega: Juzna
// 3. Konstruktor s polnimi parametri:
List<string> sorte = new List<string> { "Chardonnay", "Merlot" };
List<Trgatev> trgatevList = new List<Trgatev>
{
new Trgatev(new DateTime(2023, 9, 20), "Chardonnay", 1000.0),
new Trgatev(new DateTime(2023, 10, 5), "Merlot", 800.0)
};
Vinograd polniVinograd = new Vinograd(
"Polni Vinograd",
3.5,
sorte,
1500, // št. trsov
LegaVinograda.Zahodna,
trgatevList
);
Console.WriteLine($"{polniVinograd.ImeVinograda}, Sorte: {string.Join(", ", polniVinograd.SorteGrozdja)}, Št. trgatev: {polniVinograd.SeznamTrgatev.Count}");
// Izhod: Polni Vinograd, Sorte: Chardonnay, Merlot, Št. trgatev: 2
Razred Vinograd ima eno glavno javno metodo:
public override string ToString();
Metoda ToString() vrne strnjen opis vinograda, vključno z imenom, površino, lego in številom trgatev.
ToString():
public override string ToString()
{
return $"{ImeVinograda} ({PovrsinaHa} ha, {Lega}), {SeznamTrgatev.Count} trgatev";
}
// Uporaba:
Console.WriteLine(polniVinograd.ToString());
// Izhod: Polni Vinograd (3.5 ha, Zahodna), 2 trgatev
CertifikatRazred Certifikat modelira certifikate, ki se podelijo vinom ali vinogradom. Vključuje standard, regijo, oceno kakovosti in datume.
Ključne lastnosti razreda Certifikat:
public string Standard { get; set; } – ime/oznaka standarda (npr. "BIO", "DOC").public string Regija { get; set; } – regija oziroma izdajalec certifikata (npr. "Slovenska Vinogradniška Zbornica").public int OcenaKakovosti { get; set; } – ocena kakovosti med 0 in 100.public DateTime DatumIzdaje { get; set; } – datum, ko je bil certifikat izdan.public DateTime DatumVeljavnosti { get; set; } – datum, do kdaj certifikat velja.Opomba: Če izpustimo datume, jih lahko nastavimo na trenutni čas (DateTime.Now) v privzetem konstruktorju.
Razred Certifikat ima dva konstruktorja:
public Certifikat()
{
OcenaKakovosti = 0;
DatumIzdaje = DateTime.Now;
DatumVeljavnosti = DateTime.Now;
}
public Certifikat(string naziv, string izdajatelj, DateTime datumIzdaje, DateTime datumVeljavnosti)
{
Standard = naziv;
Regija = izdajatelj;
OcenaKakovosti = 0; // privzeta ocena, se lahko nastavi kasneje
DatumIzdaje = datumIzdaje;
DatumVeljavnosti = datumVeljavnosti;
}
Opis konstruktorjev:
OcenaKakovosti = 0 in oba datuma na sedanjost. Uporabno za dinamično ustvarjanje certifikata v UI-ju, kjer se kasneje vnesejo vse vrednosti.Certifikat:
// 1. Privzeti konstruktor:
Certifikat osnovniCert = new Certifikat();
Console.WriteLine($"Standard: {osnovniCert.Standard}, Datum izdaje: {osnovniCert.DatumIzdaje}");
// Izpis: Standard: , Datum izdaje: (trenutni datum in čas)
// 2. Konstruktor z argumenti:
Certifikat bioCert = new Certifikat(
"BIO",
"Slovenska Vinogradniška Zbornica",
new DateTime(2023, 1, 1),
new DateTime(2025, 12, 31)
);
Console.WriteLine($"Standard: {bioCert.Standard}, Veljaven do: {bioCert.DatumVeljavnosti:dd.MM.yyyy}");
// Izhod: Standard: BIO, Veljaven do: 31.12.2025
Razred Certifikat vsebuje dve prepisani metodi:
sealed override string ToString();
override DateTime PodaljsajCertifikat();
ToString()Vrne povzetek certifikata, vključno s standardom, regijo, datumom veljavnosti in oceno kakovosti.
public sealed override string ToString()
{
return $"Certifikat {Standard}, Regija: {Regija}, Veljavnost: {DatumVeljavnosti:dd.MM.yyyy}, Ocena: {OcenaKakovosti}";
}
ToString():
Console.WriteLine(bioCert.ToString());
// Izpis: Certifikat BIO, Regija: Slovenska Vinogradniška Zbornica, Veljavnost: 31.12.2025, Ocena: 0
PodaljsajCertifikat()Podaljša DatumVeljavnosti za eno leto (lahko priredimo logiko po potrebi). Vrne novi datum veljavnosti.
public override DateTime PodaljsajCertifikat()
{
DatumVeljavnosti = DatumVeljavnosti.AddYears(1);
return DatumVeljavnosti;
}
PodaljsajCertifikat():
DateTime novaVelj = bioCert.PodaljsajCertifikat();
Console.WriteLine($"Nova veljavnost: {novaVelj:dd.MM.yyyy}");
// Izpis: Nova veljavnost: 31.12.2026
VinogradnistvoRazred Vinogradnistvo upravlja z zbirkami vin, vinogradov in delavcev. Z njim lahko dodajamo nove elemente, izračunavamo skupno vrednost, dodajamo zaslužke delavcem in jih izplačujemo.
Razred Vinogradnistvo vsebuje tri glavne lastnosti (seznami):
public List<Vino> SeznamVin { get; set; } – seznam vseh vin, ki jih imamo v skladišču ali v ponudbi.public List<Vinograd> SeznamVinogradov { get; set; } – seznam vseh naših vinogradov.public List<Delavec> SeznamDelavcev { get; set; } – seznam vseh zaposlenih ali sezonskih delavcev.Opomba: vse tri zbirke inicializiramo kot novi prazni seznami v konstruktorju, da ne pride do null napak.
Razred Vinogradnistvo ima tri konstruktorje:
public Vinogradnistvo()
{
SeznamVin = new List<Vino>();
SeznamVinogradov = new List<Vinograd>();
SeznamDelavcev = new List<Delavec>();
}
public Vinogradnistvo(List<Vino> sezVin, List<Vinograd> sezVinogradov, List<Delavec> sezDelavcev)
{
SeznamVin = sezVin;
SeznamVinogradov = sezVinogradov;
SeznamDelavcev = sezDelavcev;
}
public Vinogradnistvo(Vinogradnistvo original)
{
SeznamVin = new List<Vino>(original.SeznamVin);
SeznamVinogradov = new List<Vinograd>(original.SeznamVinogradov);
SeznamDelavcev = new List<Delavec>(original.SeznamDelavcev);
}
Opis konstruktorjev:
Vinogradnistvo, vključno z novimi instancami seznamov (deep copy vsaj na ravni seznama, a elementi ostanejo iste reference). To je koristno za začasno testiranje sprememb, ne da bi posegali v originalne zbirke.Vinogradnistvo:
// 1. Privzeti konstruktor:
Vinogradnistvo prazno = new Vinogradnistvo();
Console.WriteLine($"Vina: {prazno.SeznamVin.Count}, Vinogradov: {prazno.SeznamVinogradov.Count}, Delavcev: {prazno.SeznamDelavcev.Count}");
// Izhod: Vina: 0, Vinogradov: 0, Delavcev: 0
// 2. Konstruktor z že obstoječimi seznami:
List<Vino> listaVin = new List<Vino>
{
new Vino("Modri Portugal", 2020, "Modri Portugal", 12.5, 50, 10.0, "Ljudsko vino"),
new Vino("Chardonnay Special", 2022, "Chardonnay", 13.5, 25, 18.0, "Polno vino")
};
List<Vinograd> listaVinogradov = new List<Vinograd>
{
new Vinograd("Glavni Vinograd", 4.0, LegaVinograda.Severna),
new Vinograd("Mali Vinograd", 1.5, LegaVinograda.Vzhodna)
};
List<Delavec> listaDelavcev = new List<Delavec>
{
new Delavec("Luka", "Markič", "Srednja šola", VlogaDelavca.Zaposlen),
new Delavec("Eva", "Kos", "Diplomiran ekonomist", VlogaDelavca.Zaposlen)
};
Vinogradnistvo mojeVinogradnistvo = new Vinogradnistvo(listaVin, listaVinogradov, listaDelavcev);
Console.WriteLine($"Vina: {mojeVinogradnistvo.SeznamVin.Count}, Vinogradov: {mojeVinogradnistvo.SeznamVinogradov.Count}, Delavcev: {mojeVinogradnistvo.SeznamDelavcev.Count}");
// Izhod: Vina: 2, Vinogradov: 2, Delavcev: 2
// 3. Kopirni konstruktor:
Vinogradnistvo kopija = new Vinogradnistvo(mojeVinogradnistvo);
Console.WriteLine($"Kopija - Vina: {kopija.SeznamVin.Count}, Vinogradov: {kopija.SeznamVinogradov.Count}, Delavcev: {kopija.SeznamDelavcev.Count}");
// Izpis: Kopija - Vina: 2, Vinogradov: 2, Delavcev: 2
Razred Vinogradnistvo vsebuje naslednje javne metode:
void DodajZasluzek(Delavec d, double znesek);
void Izplacaj(Delavec d);
override string ToString();
DodajZasluzek(Delavec d, double znesek)Ta metoda poišče delavca d v seznamu SeznamDelavcev in mu doda znesek k d.Zasluzi. Če delavca ni v seznamu, lahko vrže izjemo (ni prikazano) ali preprosto ne naredi nič (odvisno od odločitve razvoja).
public void DodajZasluzek(Delavec d, double znesek)
{
var najden = SeznamDelavcev.FirstOrDefault(x => x.Ime == d.Ime && x.Priimek == d.Priimek);
if (najden == null)
throw new InvalidOperationException("Delavec ne obstaja v seznamu.");
najden.Zasluzi += znesek;
}
DodajZasluzek:
// Predpostavimo, da sta dva delavca že v SeznamDelavcev:
Delavec liza = mojeVinogradnistvo.SeznamDelavcev[1]; // "Eva Kos"
mojeVinogradnistvo.DodajZasluzek(liza, 300.0);
Console.WriteLine($"Eva zasluži: {liza.Zasluzi} EUR");
// Izhod: Eva zasluži: 300 EUR
Izplacaj(Delavec d)Izplača delavca d, kar pomeni, da prenese vso vrednost d.Zasluzi v zunanjo transakcijo, dodeli d.Zasluzi = 0 in lahko spremeni d.Razpolozljiv = false.
public void Izplacaj(Delavec d)
{
var najden = SeznamDelavcev.FirstOrDefault(x => x.Ime == d.Ime && x.Priimek == d.Priimek);
if (najden == null)
throw new InvalidOperationException("Delavec ne obstaja v seznamu.");
if (!najden.Razpolozljiv)
throw new InvalidOperationException("Delavec ni razpoložljiv za izplačilo.");
double znesek = najden.Zasluzi;
// Tu bi posredovali denar na račun delavca …
najden.Zasluzi = 0.0;
najden.Razpolozljiv = false;
}
Izplacaj:
Delavec eva = mojeVinogradnistvo.SeznamDelavcev[1]; // "Eva Kos"
mojeVinogradnistvo.DodajZasluzek(eva, 300.0);
Console.WriteLine($"Pred izplačilom: {eva.Zasluzi}");
// Izhod: Pred izplačilom: 300
mojeVinogradnistvo.Izplacaj(eva);
Console.WriteLine($"Po izplačilu: {eva.Zasluzi}, Razpoložljiv: {eva.Razpoložljiv}");
// Izhod: Po izplačilu: 0, Razpoložljiv: False
ToString()Vrne povzetek stanja celotnega Vinogradnistvo:
public override string ToString()
{
return $"Vinogradništvo: {SeznamVin.Count} vino, {SeznamVinogradov.Count} vinograd, {SeznamDelavcev.Count} delavci";
}
ToString():
Console.WriteLine(mojeVinogradnistvo.ToString());
// Izhod: Vinogradništvo: 2 vino, 2 vinograd, 2 delavci
ZejniStajercRazred ZejniStajerc skrbi za branje in pisanje podatkov (vin, vinogradov, delavcev, trgatev) iz/na zunanji vir (CSV datoteke). Omogoča tudi prijavo dogodekov za uspešno/neuspešno branje in pisanje.
Razred ZejniStajerc definira delegat in eno ali več dogodkov, ki se sprožijo ob uspehu ali neuspehu operacije branja/pisanja. To omogoča, da se drugi deli aplikacije (npr. UI) lahko prijavijo (subscribe) in reagirajo:
public delegate void Obvestilo(string sporocilo);
public static event Obvestilo UspesnoBranje;
public static event Obvestilo NeuspesnoBranje;
public static event Obvestilo UspesnoPisanje;
public static event Obvestilo NeuspesnoPisanje;
Ob prijavi dogodka izvajamo kodo, ki npr. prikaže obvestilo uporabniku ali zapiše v log datoteko.
// Prijavimo se na dogodke:
ZejniStajerc.UspesnoBranje += (msg) => Console.WriteLine($"OK: {msg}");
ZejniStajerc.NeuspesnoBranje += (msg) => Console.WriteLine($"Napaka pri branju: {msg}");
ZejniStajerc.UspesnoPisanje += (msg) => Console.WriteLine($"Uspešno shranjeno: {msg}");
ZejniStajerc.NeuspesnoPisanje += (msg) => Console.WriteLine($"Napaka pri pisanju: {msg}");
Razred ZejniStajerc ima več statičnih metod za branje in pisanje CSV datotek:
static void LogException(Exception ex, string opis);
static List<Vino> ReadVinoCsv(string potDoDatoteke);
static List<Vinograd> ReadVinogradCsv(string potDoDatoteke);
static List<Delavec> ReadDelavecCsv(string potDoDatoteke);
static List<Trgatev> ReadTrgatevCsv(string potDoDatoteke);
static void WriteVinoCsv(string potDoDatoteke, List<Vino> vina);
static void WriteVinogradCsv(string potDoDatoteke, List<Vinograd> vinogradi);
static void WriteDelavecCsv(string potDoDatoteke, List<Delavec> delavci);
static void WriteTrgatevCsv(string potDoDatoteke, List<Trgatev> trgateve);
Opis metod:
LogException(Exception ex, string opis) – interni zapis napake v log, lahko vpiše sporočilo z datumom in opisom.ReadVinoCsv(string pot) – prebere seznam Vino iz CSV datoteke. Ob uspehu sproži UspesnoBranje, ob napaki NeuspesnoBranje.ReadVinogradCsv(string pot) – prebere seznam Vinograd iz CSV datoteke.ReadDelavecCsv(string pot) – prebere seznam Delavec iz CSV datoteke.ReadTrgatevCsv(string pot) – prebere seznam Trgatev iz CSV datoteki.WriteVinoCsv(string pot, List<Vino> vina) – zapiše seznam Vino v CSV datoteko. Ob uspehu sproži UspesnoPisanje, v nasprotnem primeru NeuspesnoPisanje.WriteVinogradCsv(string pot, List<Vinograd> vinogradi) – zapiše seznam Vinograd v CSV datoteko.WriteDelavecCsv(string pot, List<Delavec> delavci) – zapiše seznam Delavec v CSV datoteko.WriteTrgatevCsv(string pot, List<Trgatev> trgateve) – zapiše seznam Trgatev v CSV datoteko.
// Branje seznama vin iz CSV:
try
{
var vina = ZejniStajerc.ReadVinoCsv("vina.csv");
Console.WriteLine($"Prebrana vina: {vina.Count}");
}
catch (Exception ex)
{
// Dogodek NeuspesnoBranje je že sprožen znotraj ReadVinoCsv
Console.WriteLine($"Napaka pri branju vin: {ex.Message}");
}
// Pisanje seznama vin v CSV:
List<Vino> mojaVinskaKolekcija = new List<Vino> { rose, cvekla };
ZejniStajerc.WriteVinoCsv("vina_izpis.csv", mojaVinskaKolekcija);
// Če je zapis uspešen, se sproži dogodek UspesnoPisanje
Main (osnovni zagon)Metoda Main je vhodna točka konzolne aplikacije. Tu običajno:
UspesnoBranje, NeuspesnoBranje, UspesnoPisanje, NeuspesnoPisanje).
static void Main(string[] args)
{
// 1. Prijava dogodkov
ZejniStajerc.UspesnoBranje += (msg) => Console.WriteLine($"OK: {msg}");
ZejniStajerc.NeuspesnoBranje += (msg) => Console.WriteLine($"Napaka pri branju: {msg}");
ZejniStajerc.UspesnoPisanje += (msg) => Console.WriteLine($"Uspešno shranjeno: {msg}");
ZejniStajerc.NeuspesnoPisanje += (msg) => Console.WriteLine($"Napaka pri pisanju: {msg}");
// 2. Branje podatkov iz CSV
try
{
var vina = ZejniStajerc.ReadVinoCsv("vina.csv");
var vinogradi = ZejniStajerc.ReadVinogradCsv("vinogradi.csv");
var delavci = ZejniStajerc.ReadDelavecCsv("delavci.csv");
var trgateve = ZejniStajerc.ReadTrgatevCsv("trgatev.csv");
// Ustvarimo instanco Vinogradnistvo z prebranimi podatki
Vinogradnistvo mojeVinogradništvo = new Vinogradnistvo(vina, vinogradi, delavci);
// 3. Preprosto izpis stanja
Console.WriteLine(mojeVinogradništvo.ToString());
// 4. Po končani uporabi shranimo spremembe v nove CSV datoteke
ZejniStajerc.WriteVinoCsv("vina_izpis.csv", mojeVinogradništvo.SeznamVin);
ZejniStajerc.WriteVinogradCsv("vinogradi_izpis.csv", mojeVinogradništvo.SeznamVinogradov);
ZejniStajerc.WriteDelavecCsv("delavci_izpis.csv", mojeVinogradništvo.SeznamDelavcev);
ZejniStajerc.WriteTrgatevCsv("trgatev_izpis.csv", trgateve);
}
catch (Exception ex)
{
Console.WriteLine($"Nepričakovana napaka v Main: {ex.Message}");
}
}
S tem zagotovimo strukturo tipične konzolne aplikacije s C# in CSV vmesnikom.
V tem razdelku prikažemo primere, kako obdelovati obstoječe sezname vin, trgatev in delavcev s pomočjo LINQ-poizvedb (lambda sintaksa). Upravljamo s CSV podatki, ki so že naloženi v sezname objektov (List<Vino>, List<Trgatev>, List<Delavec>, List<Certifikat>).
Najprej predpostavimo, da imamo naložen seznam List<Vino> seznamVin in da je vsak Vino objekt povezan z lastnostjo Certifikat. Ta certifikat vsebuje lastnost DatumVeljavnosti tipa DateTime. Želimo filtrirati vsa vina, katerih potekli certifikat je že pretekel (DatumVeljavnosti < DateTime.Now), jih izpisati na zaslon in zapisati v CSV datoteko poteceni_certifikati.csv. Nato ta vina odstranimo iz glavnega seznama vin.
var poteceni = seznamVin
.Where(v => v.Certifikat != null && v.Certifikat.DatumVeljavnosti < DateTime.Now)
.ToList();
// Izpis na zaslon:
Console.WriteLine("Potekeni certifikati:");
foreach (var v in poteceni)
{
Console.WriteLine($"{v.Ime}, Certifikat veljaven do: {v.Certifikat.DatumVeljavnosti:dd.MM.yyyy}");
}
// Zapis v CSV (z glavo):
var poteceniCsv = new List<string>
{
"Ime,DatumVeljavnosti"
};
poteceniCsv.AddRange(
poteceni.Select(v => $"{v.Ime},{v.Certifikat.DatumVeljavnosti:yyyy-MM-dd}")
);
File.WriteAllLines("poteceni_certifikati.csv", poteceniCsv);
// Odstranitev poteklih iz glavnega seznama:
seznamVin = seznamVin.Except(poteceni).ToList();
poteceni_certifikati.csv vsebovala glavo in nato imena vin s pretečenimi certifikati, formatirano kot: Ime, YYYY-MM-DD. Hkrati pa so ta vina odstranjena iz seznamVin.Imamo naložen seznam List<Trgatev> seznamTrgatev. Želimo seznam urediti tako, da je najprej celotna razvrstitev po datumu trgatve naraščajoče, znotraj istega meseca pa elemente razvrstimo po količini pridelanega grozdja padajoče. Nato ta urejeni seznam izpišemo in ga zapišemo v CSV urejen_seznam_trgatev.csv.
// 1. Urejanje:
var urejeno = seznamTrgatev
.OrderBy(t => new DateTime(t.DatumTrgatve.Year, t.DatumTrgatve.Month, 1))
.ThenByDescending(t => t.KolicinaGrozdjaKg)
.ToList();
// 2. Izpis na zaslon:
Console.WriteLine("Urejene trgatve:");
foreach (var t in urejeno)
{
Console.WriteLine($"{t.DatumTrgatve:dd.MM.yyyy}, {t.SortaGrozdja}, {t.KolicinaGrozdjaKg} kg");
}
// 3. Zapis v CSV (z glavo):
var vrsticaTrgatev = new List<string>
{
"DatumTrgatve,SortaGrozdja,KolicinaGrozdjaKg,SladkornaStopnja"
};
vrsticaTrgatev.AddRange(
urejeno.Select(t =>
$"{t.DatumTrgatve:yyyy-MM-dd},{t.SortaGrozdja},{t.KolicinaGrozdjaKg},{t.SladkornaStopnja}")
);
File.WriteAllLines("urejen_seznam_trgatev.csv", vrsticaTrgatev);
YYYY-MM-DD, Sorta, Kolicina, SladkornaStopnja, urejeno po mesecih (naraščajoče) in v istem mesecu po količini grozdja (padajoče).Želimo ugotoviti, kateri delavci so sodelovali pri največ trgatvah. Uporabimo List<Trgatev> seznamTrgatev, kjer ima vsaka Trgatev lastnost List<Delavec> Udelezenci. Skupno število trgatev za posameznega delavca je število pojavitev v teh seznamih. Izpišemo top 5 delavcev na zaslon.
// 1. Združevanje in štetje:
var top5Delavcev = seznamTrgatev
.SelectMany(t => t.Udelezenci)
.GroupBy(d => d)
.Select(grp => new { Delavec = grp.Key, SteviloTrgatev = grp.Count() })
.OrderByDescending(x => x.SteviloTrgatev)
.Take(5)
.ToList();
// 2. Izpis:
Console.WriteLine("Top 5 delavcev z največ trgatvami:");
foreach (var x in top5Delavcev)
{
Console.WriteLine($"{x.Delavec.Ime} {x.Delavec.Priimek}: {x.SteviloTrgatev} trgatev");
}
Ime Priimek: Število trgatev, urejeno od največ do najmanj. Če je manj kot 5 unikatnih delavcev, se izpišejo vsi.Želimo izračunati, kakšna je bila povprečna količina grozdja (v kg) za vsakega meseca (ne glede na leto ali pa upoštevamo leto). Vzemimo List<Trgatev> seznamTrgatev in razvrstimo po letu in mesecu, nato izračunamo povprečje.
// 1. Grupiranje po letu in mesecu:
var povprecjePoMesecih = seznamTrgatev
.GroupBy(t => new { t.DatumTrgatve.Year, t.DatumTrgatve.Month })
.Select(grp => new
{
Leto = grp.Key.Year,
Mesec = grp.Key.Month,
Povp = grp.Average(x => x.KolicinaGrozdjaKg)
})
.OrderBy(x => x.Leto).ThenBy(x => x.Mesec)
.ToList();
// 2. Izpis:
Console.WriteLine("Povprečna količina grozdja po mesecih:");
foreach (var x in povprecjePoMesecih)
{
Console.WriteLine($"{x.Leto}-{x.Mesec:00}: {x.Povp:F2} kg");
}
YYYY-MM: Povprečje kg, urejeno kronološko po letu in mesecu.Želimo najti vino z veljavnim certifikatom (Certifikat.DatumVeljavnosti ≥ DateTime.Now), ki ima najstarejši letnik (LetoTrgatve najmanjša vrednost). Uporabimo List<Vino> seznamVin.
// 1. Filtriranje samo veljavnih in razvrstitev po letniku:
var najstarejsiVeljavni = seznamVin
.Where(v => v.Certifikat != null && v.Certifikat.DatumVeljavnosti >= DateTime.Now)
.OrderBy(v => v.LetoTrgatve)
.FirstOrDefault();
// 2. Izpis:
if (najstarejsiVeljavni != null)
{
Console.WriteLine($"Najstarejše vino z veljavnim certifikatom: " +
$"{najstarejsiVeljavni.Ime} ({najstarejsiVeljavni.LetoTrgatve}), " +
$"Certifikat veljaven do: {najstarejsiVeljavni.Certifikat.DatumVeljavnosti:dd.MM.yyyy}");
}
else
{
Console.WriteLine("Ni najdenega vina z veljavnim certifikatom.");
}
© Na voljo vsem razvijalcem – dokumentacija za kodo NPVaje.