Ez alapján az egyszer megírt metódus akárhányszor végrehajtható.
A metódusoknak 2 fő típusa van:
- Rutin / Routine
- Függvény / Function
A kettő közt az egyetlen különbség, hogy a rutinoknak nincs visszatérése míg a függvényeknek van. De erről később.
Írjunk programot, ami kiírja az első 10 szám négyzetét, ha az osztható 3-mal.
(Azért nem játékfejlesztői példákat adok, hogy azok egyszerűek maradhassanak és ezáltal az aktuálisan tárgyalt programozási fogalomra tudjunk koncentrálni.)
for (int i = 1; i <= 10; i++) // Elszámolunk 10-ig.
{
int pow2 = i * i; // Kiszámoljuk a szám négyzetét.
if(pow2 % 3 == 0) // Ha a négyzet maradék nélkül osztható 3-mal,
{
Debug.Log(pow2); // kiírjuk a négzetet.
}
}
Ahelyett, hogy a kódrészletet átmásolnánk több helyre, létre hozhatunk egy metódust a célra.
void MyNewMethod()
{
for (int i = 1; i <= 10; i++) // Elszámolunk 10-ig.
{
int pow2 = i * i; // Kiszámoljuk a szám négyzetét.
if(pow2 % 3 == 0) // Ha a négyzet maradék nélkül osztható 3-mal,
{
Debug.Log(pow2); // kiírjuk a négzetet.
}
}
}
Ezután a metódust egyszerűen csak meg kell hívnunk onnan, ahonnan szeretnénk.
MyNewMethod(); // Egyszer meghívom a metódust.
MyNewMethod(); // Más helyen is meghívom ugyanazt a metódust.
MyNewMethod();
// Így háromszor hajtottam végre a metódust:
// Háromszor egymás után írtam ki az első 10 szám négyzetét, ha az osztható 3-mal.
Ezzel a megoldással, ha változtatni akarok valamit a műveleten (pl. most már az 5-tel osztható négyzeteket akarom kiírni), akkor azt már csak egy helyen kell átírni.
A metódusok paraméterezése
Lehetőség van egy metódust úgy megírni, hogy minden végrehajtáskor paramétereket adhatunk át neki. Ezáltal bővíthetjük egy metódus felhasználási lehetőségeit.
Például képzeljük el az előző feladatot így megadva:
Írjunk programot, ami kiírja az első N szám négyzetét, ha az osztható M-mel.
Ebben az esetben az N és M paraméterek, amiket hívásonként lehet változtatni. Ekkor a metódus így nézne ki:
void MyNewMethod(int n, int m) // A metódus vár két int típusú n és m paramétert.
{
for (int i = 1; i <= n; i++) // Elszámolunk n-ig.
{
int pow2 = i * i; // Kiszámoljuk a szám négyzetét.
if(pow2 % m == 0) // Ha a négyzet maradék nélkül osztható m-mel,
{
Debug.Log(pow2); // kiírjuk a négzetet.
}
}
}
// (Valós esetben a paraméterek is kapjanak beszédesebb nevet!)
Így kéne meg hívni a metódust:
// Írjuk ki az első 10 szám négyzetét, ha az osztható 3-mal:
MyNewMethod(10, 3);
// Írjuk ki az első 25 szám négyzetét, ha az osztható 4-gyel:
MyNewMethod(25, 4);
// Írjuk ki az első 99 szám négyzetét, ha az osztható 2-vel:
MyNewMethod(99, 2);
// ...
Paraméterek megadásánál a sorrend számít.
Különböző típusú paramétereket is adhatunk.
Több metódust létrehozhatunk azonos névvel, de különböző paraméterezéssel. Ezt nevezzük method overload-nak
Függvények / Functions
A void kulcsszó a metódusok elején azt jelzi, hogy az adott metódus egy rutin, azaz nincs visszatérési értéke, nincs semmilyen kimenő adata.
Ezzel szemben a függvények void helyett egy értékkel térnek vissza, méghozzá olyan típusú értékkel, amit a fejléc legelején megadunk.
Hogy ez érthetőbb legyen, írjunk egy példát! Legyen ez az abszolútérték függvény!
// A következő függvény megadja egy szám abszolútértékét:
float AbsoluteValue(float number) // float típusú függvény 1 db float típusú bemenettel.
{
float result; // Ebbe a változóba fogom tárolni az eredményt.
if (number >= 0) // Ha a bemeneti szám nulla vagy pozítív, akkor...
result = number; // ...az eredmény a bemenet maga.
else // Különben, (ha negatív), akkor ...
result = -number; // ... az eredmény bemenet negáltja. (Pl.: -36 -> 36)
return result; // A függvény végén visszatérek az eredménnyel.
}
Mint láthattuk, a return
kulcsszóval tudunk visszatérni, azaz kilépni a függvényből.
Függvények esetén a return
kulcsszó után mindenképp kell egy megfelelő típusú kifejezést írni, tehát minden függvény kötelező, hogy visszatérjen egy értékkel.
A megírt függvényünket így tudjuk újra és újra felhasználni:
void Start()
{
// Számoljuk ki 10.1 abszolútértékét:
float abs1 = AbsoluteValue(10.1f);
// Számoljuk ki -25 abszolútértékét:
float abs2 = AbsoluteValue(-25);
// Számoljuk ki -24.56 abszolútértékét:
float abs3 = AbsoluteValue(-24.56f);
// ...
}
(Az Abszolútérték függvényt egyébként már megírták helyettünk a Math (Unity alatt Mathf) osztályban: Lásd később: Egyéb matematikai műveletek)
A visszatérés / return
A visszatérésre lehet úgy tekinteni, mint a függvény kimenetére, a paraméterekre pedig mint a függvény bemeneteire.
Egy függvénynek több helyen is lehet kilépési pontja. Például az abszolútérték függvényünket így is megírhattuk volna:
float AbsoluteValue(float number) // float típusú függvény egy float típusú bemenettel.
{
if (number >= 0) // Ha a szám nulla vagy pozítív,
return number; // az eredmény önmaga: ezzel térünk vissza.
else // Különben, (ha negatív)
return -number; // az eredmény önmagának negáltja: ezzel térünk vissza.
}
Ebben az esetben két lehetséges ponton tudunk kilépni a függvényből.
Arra kell figyelni egy függvény megírásánál, hogy minden lehetséges ág visszatérjen. Ha ezt nem tesszük meg, az fordítási idejű hibát eredményez és a programunk nem fog lefutni.
Egy rutinból (visszatérési érték nélküli, void metódusból) is bármikor ki tudunk lépni a return
kulcsszóval. Ebben az esetben nem kell és nem is írhatunk értéket a return
után, csak a pontosvesszőt.
A metódusok haszna
A metódus egyike a legelemibb és legfontosabb programozói eszközeinknek.
A metódusok kivételesen hasznos eszközök a kód újra-felhasználhatósága szempontjából és elengedhetetlenek a kódduplikáció elkerülésére.
Ha sok helyen használjuk ugyanazt a kódrészletet, akkor nem kell újra is újra megírni azt. Ha mégis így tennénk akkor kódduplikációt követnénk el.
A kódduplikáció nagyon hamar nehezen fenntartható, rossz minőségű kódot eredményez, hiszen ha változtatni akarunk rajta, azt sok helyen egyszerre kell elvégezni és ha egyet-egyet kifelejtünk az nehezen felismerhető és javítható inkonzisztens futáshoz vezet. Igyekezzünk kerülni ezeket.
A jövőben több eszközt is meg fogunk tanulni, amik segítségünkre lesznek ebben.
Nem csak akkor van értelme metódust írnunk, ha többször akarjuk felhasználni azt és el akarjuk kerülni az ebből adódó kódduplikációt. Egy másik, nagyon hasznos funkciója is van a metódusoknak.
Az áttekinthetetlenül bonyolult kódunkat metódusok segítségével feloszthatjuk kezelhető és átlátható részproblémákra, a részproblémákat újabb részproblémákra és így tovább addig a pontig, amíg a részfeladatok már elemi műveletekkel, mint szorzás osztás, összeadás, kivonás, stb. megoldható.
Ezáltal a szoftverünket úgy nevezett absztrakciós rétegekbe szervezzük és minden absztakciós réteg csak az eggyel alatta lévővel kommunikál (hívja annak metódusait).
Így lehetséges az, hogy olyan komplex szoftvereket tudjunk írni és futtatni, amik olyan összetett problémákat oldanak meg végtelenül összetett működéssel, amikkel a mindennapi életünkben találkozhatunk. Amellett, hogy ezen programok is, elemi szinten csak egyszerű matematikai és logikai műveletek összessége.
Függvények több kimenő adattal (Kiegészítő anyag)
⚠️ Figyelmeztetés! Ezzel egy több helyen is előre ugrunk az anyagban. ⚠️
Alapvetően egy függvény egy kimenettel, egy visszatérési értékkel rendelkezik. Viszont ha egy metódusból több adatot szeretnénk “kivezetni” akkor több lehetőségünk van.
- Definiálunk egy összetett típust, osztályt vagy struktúrát. Abba tesszük az összes kimeneti adatot és egy adott példánnyal térünk vissza.
- Anonim összetett típussal térünk vissza.
- out paraméterek használata.
- Ha egy referenciatípusú adatot használunk paraméternek, és ezen az objektumon változtatunk metóduson belül, annak hatása érzékelhető lesz a hívás után is.
- Addattípusú paramétereken is nyilatkozhatunk arról, hogy referenciaként történjen az átadás a
ref
kulcsszóval.
Lásd később: Összetett típusok és példányaik
Ez a megoldás hasonló az előzőhöz anélkül, hogy külön definiálnánk a típust.
Használata nem javasolt. Nem kommunikálja le jól a fejlesztő szándékát.
Ha egy out kulcsszót teszünk egy paraméter elé azzal jelezzük, hogy az egy kimenő adat lesz.
float square5 = Square(5, out string square5Text);
Console.WriteLine(square5Text);
float Square (float num, out string text)
{
text = "A szám négyzete: " + (num * num);
return num * num;
}
Az alábbi példában tömböket használok fel, amikről később tanulunk majd: Tömbök
int[] array = new int[10]; // A tömb egy referenciatípusú
Fill(array);
Console.WriteLine(array[3]); // 3
void Fill(int[] array)
{
for (int i = 0; i < array.Length; i++)
array[i] = i;
}
Ennek az oka az adat átadásának módjában keresendő: Referencia- és értéktípusok
int n = 5;
DoubleOf(ref n);
Console.WriteLine(n); // 10
void Double(ref int num)
{
num *= 2;
}
Részletes leírás itt: Függvények több kimenő adattal
A Unity Üzenet-metódusok (Kiegészítő anyag)
A Unity-ben léteznek bizonyos speciális úgynevezett üzenetmetódusok, amiket a Unity maga hív, minden MonoBehavior komponensen a betöltött Scene-ben bizonyos események hatására.
- void
Start()
- Miután a komponens egy példánya létrejött. - void
Update()
- Minden képfrissítés előtt.
A jövőben sok ehhez hasonló Unity metódust fogunk még tanulni.
Ezeket csakis abban az esetben fogja a Unity hívni, ha teljesen megfelelő a fejléc:
- Helyes a visszatérés típusa (általában void)
- Helyes a metódus azonosítója
- Helyesek a paraméterek típusa és sorrendje.
Lásd bővebben: Hello Unity: Első Unity programunk, MonoBehaviour-ok életciklusa