Objektumorientált programozás (OOP)¶
A C# osztályokkal írja le az adatokat és a hozzájuk tartozó műveleteket. A Python class fogalma itt is érvényes: az osztály tervrajz, az objektum pedig egy példány. Az OOP fontos fogalmai az egységbezárás, az öröklődés és a polimorfizmus.
Osztály létrehozása¶
A Szemely osztályban az adatoknak típust adunk. A private mezők kívülről közvetlenül nem érhetők el. C#-ban az osztály alapértelmezett láthatósága internal, ezért itt kifejezetten public-ot írunk.
Pythonban az attribútumokat rendszerint a __init__ metódusban hozzuk létre, és a név előtti _ inkább konvenciót jelez, nem ugyanolyan hozzáférési korlát, mint a C# private.
Konstruktor és túlterhelés¶
A konstruktor neve megegyezik az osztály nevével. A this az aktuális példányra mutat, mint Pythonban a self. Több konstruktort is írhatunk eltérő paraméterlistával.
public class Szemely
{
private string nev;
private int eletkor;
public Szemely(string nev, int eletkor)
{
this.nev = nev;
this.eletkor = eletkor;
}
public Szemely() : this("Ismeretlen", 18)
{
}
}
Pythonban ugyanezt általában alapértelmezett paraméterértékekkel oldjuk meg: def __init__(self, nev="Ismeretlen", eletkor=18): ....
Tulajdonságok, getter és setter¶
A Java getNev() és setNev() metódusainak C#-ban gyakori megfelelője a property. A kívülről olvasható és ellenőrzötten írható adathoz így készülhet tulajdonság:
public class Szemely
{
private string nev;
private int eletkor;
public Szemely(string nev, int eletkor)
{
this.nev = nev;
Eletkor = eletkor;
}
public string Nev
{
get => nev;
set => nev = string.IsNullOrWhiteSpace(value) ? "Ismeretlen" : value;
}
public int Eletkor
{
get => eletkor;
set
{
if (value < 0) throw new ArgumentOutOfRangeException(nameof(value));
eletkor = value;
}
}
public override string ToString() => $"{Nev} ({Eletkor} éves)";
}
A get lekérdez, a set módosít; a value a beállítani kívánt érték. A ToString() a Python __str__ metódusához hasonló. Egyszerű, külön ellenőrzést nem igénylő adatnál automatikus tulajdonság is elég: public string Nev { get; set; } = "";.
Példányosítás¶
Szemely valaki = new("Kis Pista", 25);
Console.WriteLine(valaki.Nev);
valaki.Nev = "Nagy Pista";
Console.WriteLine(valaki); // ToString() automatikusan meghívódik
Szemely masik = new(); // alapértelmezett konstruktor
Pythonban: valaki = Szemely("Kis Pista", 25); a new kulcsszót nem írjuk ki.
Láthatóság¶
| C# módosító | Hol érhető el? |
|---|---|
public |
bárhonnan |
private |
az osztályon belül |
protected |
az osztályban és leszármazottaiban |
internal |
ugyanabban a projektben / assemblyben |
Az osztálytagok alapértelmezett láthatósága private. Az adatokhoz gyakran nyilvános tulajdonságon keresztül férünk hozzá.
Öröklődés¶
A C#-ban a : jelöli az ősosztályt. A gyermek konstruktorából a base(...) hívja az ős konstruktorát. Felülírható metódushoz az ősben virtual, a gyermekben override szükséges.
classDiagram
Jarmu <|-- Auto
Jarmu <|-- Motor
Jarmu : +string Szin
Jarmu : +Dudal()
Auto : +int AjtokSzama
Motor : +bool VanCsomagtarto
public class Jarmu
{
public string Szin { get; }
public Jarmu(string szin)
{
Szin = szin;
}
public virtual void Dudal()
{
Console.WriteLine("Pípí");
}
}
public class Auto : Jarmu
{
public int AjtokSzama { get; }
public Auto(string szin, int ajtokSzama) : base(szin)
{
AjtokSzama = ajtokSzama;
}
public override void Dudal()
{
Console.WriteLine("Tütü");
}
}
public class Motor : Jarmu
{
public bool VanCsomagtarto { get; }
public Motor(string szin, bool vanCsomagtarto) : base(szin)
{
VanCsomagtarto = vanCsomagtarto;
}
public override void Dudal()
{
Console.WriteLine("Brrr");
}
}
List<Jarmu> jarmuvek = new() { new Auto("piros", 5), new Motor("kék", false) };
foreach (Jarmu jarmu in jarmuvek)
{
jarmu.Dudal(); // a tényleges példány metódusa fut le
}
Pythonban a gyermekosztály alakja class Auto(Jarmu):, az ős konstruktorát super().__init__(...) hívja. A metódus felülírásához nincs virtual/override kulcsszó.
Feladat: érdemjegyek súlyozott átlaga¶
A Java-fejezethez hasonlóan készíts Erdemjegy osztályt: tárold a dátumot, a jegyet, a típust és a súlyt. Az adatokat egyszerű dátum;jegy;típus;súly sorokból olvasd. A súlyozott átlag képlete:
public class Erdemjegy
{
public string Datum { get; }
public int Jegy { get; }
public string Tipus { get; }
public int Suly { get; }
public Erdemjegy(string datum, int jegy, string tipus, int suly)
{
Datum = datum;
Jegy = jegy;
Tipus = tipus;
Suly = suly;
}
}
List<Erdemjegy> jegyek = new();
foreach (string sor in File.ReadLines("jegyek.csv"))
{
string[] mezok = sor.Split(';');
if (mezok.Length != 4 ||
!int.TryParse(mezok[1], out int jegy) ||
!int.TryParse(mezok[3], out int suly) || suly <= 0)
{
Console.WriteLine($"Hibás sor: {sor}");
continue;
}
jegyek.Add(new Erdemjegy(mezok[0], jegy, mezok[2], suly));
}
int sulyokOsszege = jegyek.Sum(j => j.Suly);
if (sulyokOsszege > 0)
{
double atlag = (double)jegyek.Sum(j => j.Jegy * j.Suly) / sulyokOsszege;
Console.WriteLine($"Súlyozott átlag: {atlag:F2}");
}
Itt a Sum a System.Linq része. A Python-megoldásban ugyanígy objektumokat gyűjthetünk listába, majd sum(j.jegy * j.suly for j in jegyek) / sum(j.suly for j in jegyek) kifejezéssel számolhatunk, ha a súlyok összege nem nulla.