2. Definicija metode
• Mora se nalaziti unutar tipa
• Sastoji se od:
– definicije prava pristupa (ako se izostavi, tada je
podrazumijevano private)
– opcijskog dodatnog atributa (static, virtual, new,
override, abstract, sealed , partial)
–
–
–
–
definicije povratnog tipa
identifikatora
liste argumenata
tijela metode
Programiranje u C♯ - 8. Metode
2
3. Primjer definicije
public virtual void ImeMetode(int prviArgument,
string drugiArgument) {
// tijelo metode
}
Programiranje u C♯ - 8. Metode
3
4. Poziv metode
• Nestatičke metode dohvaćaju se preko instance tipa koji
sadrži metodu:
MojaKlasa mk = new MojaKlasa();
mk.JavnaMetoda(); // poziv javno dostupne
// nestatičke m.
• Statičke metode se dohvaćaju preko imena tipa:
MojaKlasa.StatickaMetoda(); // poziv javno dostupne
// statičke metode
Programiranje u C♯ - 8. Metode
4
5. Poziv metode
• Pokuša li se pozvati metoda koja nije dostupna (zbog
privatnog ili zaštićenog prava pristupa), prevoditelj će javiti
pogrešku
• Ako se poziva metoda kojoj proslijeĎeni parametri ne
odgovaraju po tipu, prevoditelj će pokušati provesti
implicitne pretvorbe parametara; ako ni one ne
omogućavaju poziv dostupne metode, prevoditelj će javiti
pogrešku
• Isto vrijedi za pridruživanje povratne vrijednosti (ako
metoda vraća neki rezultat)
Programiranje u C♯ - 8. Metode
5
6. Preopterećenje metode
• Metode se prepoznaju prema nazivu (identifikatoru)
metode
• Moguće je isti identifikator upotrijebiti za dvije ili više
metoda unutar tipa, ako se one razlikuju po potpisu
(signature)
• Potpis metode, osim naziva čine parametri metode (njihov
tip i redoslijed)
• Ako postoje dvije ili više istoimene metode koje se
razlikuju, govorimo o preopterećenju (overloading) metode
Programiranje u C♯ - 8. Metode
6
7. Preopterećenje metode
• Primjer:
public static class Console {
public static void WriteLine() { ... }
public static void WriteLine(Boolean) { ... }
public static void WriteLine(Char) { ... }
// itd.
}
• Povratni tip ne spada u potpis metode pa će stoga
prevoditelj u donjem primjeru prijaviti pogrešku:
class MojaKlasa {
public void MojaMetoda() { ... }
// pogreška: postoji već MojaMetoda s istim potpisom
private double MojaMetoda() { ... }
}
Programiranje u C♯ - 8. Metode
7
8. Poziv preopterećenih metoda
• Preopterećenje omogućava da se isti identifikator koristi
za različite parametre
• Ovisno o konkretnim parametrima, prevoditelj će pozvati
odgovarajuću verziju
• Ako ne postoji verzija s točno odgovarajućim tipovima i
redoslijedom parametara, prevoditelj pokušava naći
verziju koja se može pozvati uz što manji broj implicitnih
pretvorbi; ako ne uspije – javlja pogrešku
Programiranje u C♯ - 8. Metode
8
9. Podrazumijevane vrijednosti
parametara
• C od verzije 4.0 omogućava definiranje
podrazumijevanih vrijednosti parametara:
class MojaKlasa {
public int Zbroji(int x = 3, int y = 4) {
return x + y;
}
}
• U pozivu se parametri s definiranim podrazumijevanim
vrijednostima mogu izostaviti:
MojaKlasa mk = new MojaKlasa();
mk.Zbroji(5, 6); // vraća 11
mk.Zbroji(5);
// ista metoda, vraća 9
mk.Zbroji();
// ista metoda, vraća 7
Programiranje u C♯ - 8. Metode
9
10. Podrazumijevane vrijednosti
parametara
• Inače se definiranje podrazumijevanih vrijednosti smatra
lošim pristupom koji treba izbjegavati, jer unosi
neodreĎenosti, posebno ako je metoda preopterećena:
class MojaKlasa {
public int Zbroji(int x = 3, int y = 4) {
return x + y;
}
public int Zbroji(int x) {
return x + 1;
}
}
mk.Zbroji(4);
// 1. koju verziju će pozvati?
// 2. ako maknemo drugu definiciju
//
rezultat će biti drugačiji!
Programiranje u C♯ - 8. Metode
10
11. Podrazumijevane vrijednosti
parametara
• “Čišće” je metode preopteretiti:
class MojaKlasa {
public int Zbroji(int x, int y) {
return x + y;
}
public int Zbroji(int x) {
return Zbroji(x, 4);
}
public int Zbroji() {
return Zbroji(3);
}
}
• No to ponekad može dovesti do “bujanja” kôda
Programiranje u C♯ - 8. Metode
11
12. Imenovani parametri
• C od verzije 4.0 omogućava imenovanje parametara pri
pozivu:
class MojaKlasa {
public int Zbroji(int x = 3, int y = 4) {
return x + y;
}
}
mk.Zbroji(x: 4);
mk.Zbroji(y: 8);
mk.Zbroji(y: 8, x: 9);
Programiranje u C♯ - 8. Metode
12
13. Prosljeđivanje parametara
• Podrazumijevano se svi parametri prenose po vrijednosti:
– za referentne tipove to znači da se prosljeĎuje
referenca na objekt (po vrijednosti) – pozivajući kôd će
vidjeti sve promjene u metodi
– za vrijednosne tipove radi se preslika objekta –
pozivajući kôd ne vidi promjene
Programiranje u C♯ - 8. Metode
13
14. Vrijednosni tip kao parametar
• Pri ulasku u metodu radi se preslika vrijednosti i metoda
radi s tom preslikom. Po izlasku iz metode, sve promjene
se gube:
void Uvecaj(int n) {
n += 1;
Console.WriteLine(n);
}
// ...
int n = 5;
Uvecaj(n);
Console.WriteLine(n);
// ispisat će 6
// ispisat će 5
Programiranje u C♯ - 8. Metode
14
15. Referentni tip kao parametar
• Pri ulasku u metodu radi se preslika reference; budući da
referenca pokazuje na isti objekt, metoda radi s originalom.
Po izlasku iz metode, sve promjene ostaju sačuvane:
class MojaKlasa {
public int N = 10;
}
void Uvecaj(MojaKlasa mk) {
mk.N += 1;
Console.WriteLine(mk.N);
}
// ...
MojaKlasa mk = new MojaKlasa();
Console.WriteLine(mk.N);
// ispisat će 10
Uvecaj(mk);
// ispisat će 11
Console.WriteLine(mk.N);
// ispisat će 11
Programiranje u C♯ - 8. Metode
15
16. Struktura kao parametar
• Struktura spada u vrijednosne tipove:
struct MojaStruktura {
public MojaStruktura(int n) { N = n; }
public int N;
}
void Uvecaj(MojaStruktura ms) {
ms.N += 1;
Console.WriteLine(ms.N);
}
// ...
MojaStruktura ms = new MojaStruktura(20);
Console.WriteLine(ms.N);
// ispisat će 20
Uvecaj(ms);
// ispisat će 21
Console.WriteLine(ms.N);
// ispisat će 20
Programiranje u C♯ - 8. Metode
16
17. Prosljeđivanje parametara po
referenci
• Da bi se neki objekt vrijednosnog tipa prenio po
referenci, treba eksplicitno navesti ključne riječi ref ili
out (ovisno o tome tko je zadužen za inicijalizaciju
objekta) ispred imena parametra:
– ref znači da je objekt inicijaliziran prije poziva, tj.
pozivajući kôd je zadužen za inicijalizaciju,
– out znači da se objekt inicijalizira u pozvanoj metodi.
Programiranje u C♯ - 8. Metode
17
18. Prosljeđivanje reference
• Da bi se neki inicijalizirani objekt prenio po referenci, treba
eksplicitno navesti ključne riječi ref:
void DodajDeset(ref int x) {
// uvećava vrijednost na koju referencira x za 10
x += 10;
}
// ...
int x = 5;
DodajDeset(ref x);
Console.WriteLine(x); // ispisuje 15
Programiranje u C♯ - 8. Metode
18
19. Prosljeđivanje neinicijaliziranih
objekata
• Ponekad trebamo metodi proslijediti neinicijalizirani objekt,
a ona ga treba inicijalizirati:
// neinicijalizirani x
int x;
InicijalizirajBroj(x);
// pogreška: korištenje
// neinicijalizirane
// varijable
Programiranje u C♯ - 8. Metode
19
20. Prosljeđivanje neinicijaliziranih
objekata
• Ključna riječ out omogućava prosljeĎivanje
neinicijaliziranih objekata:
void InicijalizirajBrojNaDeset(out int x) {
// postavlja vrijednost na koju referencira x
// na 10
x = 10;
}
int x;
InicijalizirajBrojNaDeset(out x);
Console.WriteLine(x);
// ispisuje 10
Programiranje u C♯ - 8. Metode
20
21. Navođenje reference u pozivu
• U pozivu metode treba eksplicitno navesti ref i out
ispred argumenta – ovo se može činiti suvišnim (i jest)
budući da je u definiciji funkcije navedeno da se
parametar prenosi po referenci
• S jedne strane, eksplicitno navoĎenje čini kôd čitljivijim
Programiranje u C♯ - 8. Metode
21
22. Navođenje reference u pozivu
• Osim toga, moguće je preopteretiti metode tako da se
razlikuju po tome da li se parametar metodi prenosi po
vrijednosti ili po referenci:
class MojaApp {
// dvije preopterećene verzije
public void DodajDeset(int x) { ... }
public void DodajDeset(ref int x) { ... }
}
U tom slučaju bez eksplicitnog navoĎenja ne bi bilo jasno
koju verziju metode treba pozvati
Programiranje u C♯ - 8. Metode
22
23. Preopterećenje metoda s
referencama kao parametrima
• Nije moguće preopterećivati metode čiji parametri se
razlikuju samo po ref i out:
class MojaApp {
public void DodajDeset(ref int x) { ... }
// pogreška: ne mogu se razlikovati samo po
// ref i out
public void DodajDeset(out int x) { ... }
}
Programiranje u C♯ - 8. Metode
23
24. Prosljeđivanje parametara
referentnog tipa po referenci
• Metoda koja radi zamjenu dva objekta referentnog tipa:
public static void Zamijeni(object o1, object o2) {
object temp = o2;
o2 = o1;
o1 = temp;
}
// ...
string prvi = "prvi";
string drugi = "drugi";
// nakon ovog poziva objekti će ostati nezamijenjeni!
Zamijeni(prvi, drugi);
Programiranje u C♯ - 8. Metode
24
25. Prosljeđivanje parametara
referentnog tipa po referenci
• Pravilna inačica bi bila:
public static void Zamijeni(ref object o1,
ref object o2) {
object temp = o2;
o2 = o1;
o1 = temp;
}
// ...
string prvi = "prvi";
string drugi = "drugi";
// nakon ovog poziva objekti će ostati nezamijenjeni!
Zamijeni(prvi, drugi);
Programiranje u C♯ - 8. Metode
25
26. Prosljeđivanje parametara
referentnog tipa po referenci
• Objekte koje metodi Zamijeni prosljeĎujemo po referenci
moraju biti reference na object tip, a ne string (time se
osigurava tipska sigurnost)
• Zbog toga moramo pisati:
string prvi = "prvi";
string drugi = "drugi";
// prilikom poziva moramo prvo dodijeliti tip Object:
object obj1 = prvi;
object obj2 = drugi;
Zamijeni(ref obj1, ref obj2);
// zamijenjenima vratimo tip string:
prvi = (string)obj1;
drugi = (string)obj2;
Programiranje u C♯ - 8. Metode
26
27. Promjenjivi broj parametara
• Ponekad je potrebno metodi proslijediti promjenjivi broj
argumenata – broj argumenata se ne zna prilikom prevoĎenja
kôda
• Funkcija koja prima promjenjivi broj argumenata deklarira se
pomoću ključne riječi params:
double Zbroji(params double[] vrijednosti) {
...
}
• Ovakav argument može se proslijediti i dalje!
Programiranje u C♯ - 8. Metode
27
28. Promjenjivi broj parametara
• Primjer poziva ovakve metode:
double zbroj = Zbroji(new double[] { 1, 2, 3 });
• MeĎutim, moguće je pozvati i na sljedeći način:
double zbroj = Zbroji(1, 2, 3);
zahvaljujući ParamArrayAttribute atributu (params je samo
kratica za njega):
double Zbroji([ParamArray] double[] vrijednosti)
• Kada prevoditelj uoči poziv metode, provjerava sve metode s tim
imenom koje ne sadrže ParamArray atribut, a koje mogu obraditi
poziv. Ako ne uspije naći, traži metode koje imaju ParamArray
atribut, te stvara kôd za poziv.
Programiranje u C♯ - 8. Metode
28
29. Promjenjivi broj parametara
• Samo zadnji parametar u definiciji funkcije može biti params:
double Zbroji(params double[] vrijednosti,
int broj)
// pogreška: params mora biti zadnji!
• Za promjenjivi broj argumenata različitog tipa:
static void Primi(params Object[] objekti) {
...
}
Programiranje u C♯ - 8. Metode
29
30. Virtualne metode
• Princip virtualnih metoda omogućava da se za odreĎeni izvedeni tip
uvijek poziva njegova metoda, čak i kada smo mu dodijelili neki bazni
tip.
class Bazna {
public virtual void NapisiMe() {
Console.WriteLine("Ja sam Bazna");
}
}
class Izvedena : Bazna {
public override void NapisiMe() {
Console.WriteLine("Ja sam Izvedena");
}
}
...
Bazna b = new Bazna();
Bazna i = new Izvedena();
b.NapisiMe();
// "Ja sam Bazna"
i.NapisiMe();
// "Ja sam Izvedena"
Programiranje u C♯ - 8. Metode
30
31. Virtualne metode
• Virtualne metode omogućavaju primjenu principa polimorfizma:
abstract class GeometrijskiLik {
public virtual void NacrtajSe() { ... }
}
class Trokut : GeometrijskiLik {
public override void NacrtajSe() { ... }
}
class Krug : GeometrijskiLik {
public override void NacrtajSe() { ... }
}
...
GeometrijskiLik[] crtez = new GeometrijskiLik[2];
crtez[0] = new Trokut();
crtez[1] = new Krug();
...
foreach (GeometrijskiLik lik in crtez) {
lik.NacrtajSe();
}
Programiranje u C♯ - 8. Metode
31
32. Virtualne metode
• Ako u baznoj klasi zaboravimo staviti virtual, prevoditelj će javiti
upozorenje – trebamo u izvedenoj klasi dodati ključnu riječ new:
class Bazna {
public void NapisiMe() {
Console.WriteLine("Bazna klasa");
}
}
class Izvedena : Bazna {
public new void NapisiMe() {
Console.WriteLine("Izvedena klasa, izvedena iz:");
base.NapisiMe();
}
}
• Modifikatorom new programer eksplicitno daje do znanja da je
“sakrio” istoimenu metodu iz baznog tipa.
• Metode nisu virtualne!
Programiranje u C♯ - 8. Metode
32
33. Virtualne metode
• Ako u izvedenoj klasi uvedemo virtualnu metodu:
class Bazna {
public void NapisiMe() {
Console.WriteLine("Bazna klasa");
}
}
class Izvedena : Bazna {
public new void NapisiMe() {
Console.WriteLine("Izvedena klasa, izvedena iz:");
base.NapisiMe();
IspisiMiClanove();
}
protected virtual void IspisiMiClanove() {
Console.WriteLine("Isključivo moji članovi su:");
// ...
}
}
33
Programiranje u C♯ - 8. Metode
34. Virtualne metode
• A potom dodamo takvu metodu i u baznoj klasi:
class Bazna {
public void NapisiMe() {
Console.WriteLine("Bazna klasa");
IspisiMiClanove();
}
protected virtual void IspisiMiClanove() {
Console.WriteLine("Isključivo moji članovi su:");
// ...
}
}
prevoditelj će javiti upozorenje da izvedena klasa skriva
istoimenu metodu IspisiMiClanove bazne klase.
Programiranje u C♯ - 8. Metode
34
35. Virtualne metode
• Da bismo osigurali da će bazna klasa uvijek pozvati svoju
IspisiMiClanove metodu, dodajemo ključnu riječ new:
class Izvedena : Bazna {
public new void NapisiMe() {
Console.WriteLine("Izvedena klasa, izvedena iz:");
base.NapisiMe();
IspisiMiClanove();
}
new protected virtual void IspisiMiClanove() {
Console.WriteLine("Isključivo moji članovi su:");
// ...
}
}
Programiranje u C♯ - 8. Metode
35
36. Parcijalne metode
• Parcijalne metode omogućavaju da je potpis metode definiran u
jednom dijelu parcijalne klase, a implementacija u drugom dijelu:
partial class PK {
partial void PM(string tekst);
}
partial class PK {
partial void PM(string tekst) {
// ...
}
}
• Ograničenja:
– potpisi metoda moraju biti identični;
– metoda mora vraćati void;
– nisu dozvoljeni modifikatori niti atributi.
Programiranje u C♯ - 8. Metode
36