D blokk · Metódusok · 3. tananyag
A D2-vel a
fejléc majdnem teljes — de három kérdés nyitva maradt. Mi van, ha
ugyanarra a műveletre többféle bemenettel is szükség
van? Ha egy paraméternek majdnem mindig ugyanaz az
értéke? És hogyan ad vissza egy metódus két
eredményt — ahogy a
TryParse teszi
a B6 óta? Ma az out titka is megfejtésre
kerül.
out-ot —
és folyékonyan olvasod a TryParse
fejlécét.ref-et, és
tudod, mikor melyik: return az alapút,
out a többlet-eredmény,
ref a helyben módosítás.Konzol.SzamotKer
tartomány-ellenőrzős változattal bővül.A D1–D2-ben vonalhúzó metódusokat írtunk — többfélét, több néven. Pedig mind ugyanazt csinálja, csak más bemenettel. C#-ban adhatjuk nekik ugyanazt a nevet:
Vonal(); // alapvonal Vonal(50); // hosszabb Vonal('=', 20); // más jelből void Vonal() { Vonal('-', 30); // a rövid alak a teljeset hívja — nincs másolás! } void Vonal(int hossz) { Vonal('-', hossz); } void Vonal(char jel, int hossz) { for (int i = 0; i < hossz; i++) { Console.Write(jel); } Console.WriteLine(); }
A Console.WriteLine is túlterhelt: hívtad
már üresen (üres sor), stringgel, számmal — és mindig „tudta”, mit
tegyen. Most már azt is tudod, miért: a fordító a szignatúrák közül
választott.
A háromalakú vonalhúzó egyetlen metódussal is megoldható:
void Vonal(char jel = '-', int hossz = 30) { for (int i = 0; i < hossz; i++) { Console.Write(jel); } Console.WriteLine(); } Vonal(); // '-' jelből 30 Vonal('='); // '=' jelből 30 Vonal('=', 20); // '=' jelből 20
= '-' a fejlécben
alapértelmezett érték: ha a hívás nem ad
argumentumot, ez lép életbe.Vonal(hossz: 10);
— a paraméter nevével címezve a sorrend is felrúgható. Ritkán kell,
de jó tudni róla.Ha az alakok csak alapértékekben térnek el: opcionális paraméter (egy törzs). Ha más a viselkedésük vagy más típusú a bemenetük: túlterhelés.
A D2-ben
rögzítettük: a metódus másolatot kap, a hívó
változójához nem nyúl. Az out
ez alól ad szabályozott kivételt: az out paraméteren keresztül a
metódus a hívó változójába ír.
Most már megírhatjuk a saját „TryParse-szabású” metódusunkat:
if (BiztonsagosOsztas(10, 3, out int hanyados)) { Console.WriteLine($"Az eredmény: {hanyados}"); } else { Konzol.Hiba("Nullával nem osztunk!"); } bool BiztonsagosOsztas(int a, int b, out int eredmeny) { if (b == 0) { eredmeny = 0; // out-nak MINDEN úton értéket kell kapnia return false; } eredmeny = a / b; return true; }
TryParse-é: a
visszatérési érték a siker (bool), az out
paraméter az eredmény. Két kimenet egy hívásból.TryParse is 0-t hibás bevitelnél.out kulcsszót ki
kell írni (CS1620): jól látszik, hogy az a változó a
hívásban íródni fog.És ezzel a B6-os rejtély teljesen megoldva — olvasd el a fejlécet, ma már minden szava ismerős:
public static bool TryParse(string s, out int result)
Az out-nál a metódus ad; a
ref-nél a metódus a hívó
meglévő értékét kapja meg és
módosíthatja:
int pontszam = 80; Bonusz(ref pontszam); Console.WriteLine(pontszam); // 90 — tényleg megváltozott! void Bonusz(ref int ertek) { ertek += 10; }
ref változónak híváskor már
legyen értéke (az out-nak nem kell).Bonusz(ref pontszam);.Az esetek túlnyomó részében egyik sem — az
alapértelmezett út a return (D2): tiszta,
követhető. Az out akkor jó, ha
két kimenet kell (siker + eredmény, vagy két
összetartozó érték); a ref ritka vendég —
akkor, ha egy meglévő értéket tényleg helyben kell átírni (pl.
csere).
Túlterhelés, opcionális paraméter, out vagy ref — a helyzet dönt.
| Tünet | Mi történt? | Mit tegyél? |
|---|---|---|
CS0111: already defines a member … with the same parameter types | két metódus azonos szignatúrával | a paraméterlistának különböznie kell — a visszatérési típus nem számít bele |
CS1737: Optional parameters must appear after all required parameters | opcionális paraméter került a kötelezők elé | az = érték-es paraméterek a lista végére |
CS0177: The out parameter … must be assigned | van kódútvonal, ahol az out nem kap értéket | minden ágon adj értéket — a hibaágon is (pl. 0) |
CS1620: Argument … must be passed with the 'out' keyword | a hívásból lemaradt az out/ref kulcsszó | írd ki a hívásban is: Metodus(out valtozo) |
CS0165 a ref-es hívásnál | a ref-ként átadott változónak még nincs értéke | ref-hez inicializált változó kell (out-hoz nem) |
| a fordító „nem találja” a hívni kívánt alakot (CS1503) | az argumentumok egyik túlterhelt alakra sem illenek | nézd végig a szignatúrákat: melyikhez igazodnak a típusaid? |
Konzol.SzamotKer-rel).Konzol.cs-be a
túlterhelt változatot:
public static int SzamotKer(string kerdes, int min, int max)
— addig kérdezzen újra, amíg a szám a határok közé nem esik
(C5-ös
do-while + C1-es feltétel), a hibaüzenet nevezze meg a
határokat.int tipp = Konzol.SzamotKer("Tipped: ", 1, 100);
— és próbáld ki tartományon kívüli számmal.Konzol.Elvalaszto-nak
opcionális paramétereket
(char jel = '─', int hossz = 28).SzamotKer tulterheles min-max hatarokkal.A SzamotKer mindkét alakja működik;
betűre, rossz számra és tartományon kívüli értékre is újrakérdez; a
kétparaméteres alak nem másolja a beolvasó ciklust.
⭐ alap · ⭐⭐ haladó · ⭐⭐⭐ kihívás
Kétalakú üdvözlés: írj Udvozol() és
Udvozol(string nev) metódust: az első
általánosan köszön, a második név szerint. A paraméter nélküli
hívja a paraméterest egy alapértelmezett szöveggel.
Keret kétféleképpen: írd meg a szöveget bekeretező metódust ELŐSZÖR
két túlterhelt alakkal (Keret(string szoveg)
és Keret(string szoveg, char jel)), MAJD
egyetlen opcionális paraméteres változattal. Melyik tetszik jobban?
Kommentben indokold.
Nagyobb, kétszer: írj int Nagyobb(int a, int b)
ÉS double Nagyobb(double a, double b)
metódust — a fordító a hívás alapján választ. Próbáld ki vegyes
hívásokkal, és figyeld meg, mikor melyik fut.
Időfelbontó: írj
void Felbont(int osszMasodperc, out int perc, out int masodperc)
metódust (B2-es
/ és %!), és
írasd ki vele a 754 másodpercet perc:másodperc alakban.
Csere: írj void Csere(ref int a, ref int b)
metódust a klasszikus háromváltozós cserével
(B9.14
emléke!) — és mutasd meg egy rövid programban, hogy a hívó
változói tényleg helyet cseréltek. Gondold végig: miért nem lehetne
ezt return-nel megoldani?
Minden kérdésnél egy válasz helyes. A végén pontszámot kapsz.
| Fogalom | Jelentés |
|---|---|
| túlterhelés (overload) | azonos nevű metódusok különböző paraméterlistával — a fordító a hívásból választ |
| szignatúra | a metódus neve + paraméterlistája — ennek kell egyedinek lennie |
| opcionális paraméter | alapértelmezett értékű paraméter (int hossz = 30) — a hívásból elhagyható |
| név szerinti argumentum | a paraméter nevével címzett átadás: Vonal(hossz: 10) |
out | a metódus a hívó változójába ír — köteles minden úton értéket adni |
ref | a metódus a hívó meglévő értékét kapja és módosíthatja |
| TryParse-minta | bool visszatérés a sikerről + out paraméter az eredménynek |
= érték), a lista végén áll —
alapérték-eltérésekre ez, viselkedés-különbségre túlterhelés.out a szabályozott
kivétel az érték szerinti átadás alól: a metódus a hívó változójába
ír, minden úton köteles értéket adni — ez a
TryParse-minta: bool siker + out eredmény.ref meglévő értéket
módosít helyben — ritkán kell; az alapút mindig a
return.Konzol.SzamotKer tartomány-ellenőrzős
alakkal bővült — a Mastermind bekérései készen állnak.public static — és mi van a top-level
programjaink mögött? A blokk zárófejezete megmutatja.