MetodyCzęść NR.4W poprzednim wpisie pokazałem jak łatwo i szybko napisać prostą aplikacje graficzną.
Jednak jak podkreśliłem w poprzednim wpisie, znajomość operacji arytmetycznych to za mało do budowania nawet takich małych programików.
Dzisiaj pokażę jak tworzyć własne metody. Jest to jeden z najprostszych trików do podzielenia kodu na mniejsze części, tak by stał się on bardziej czytelny.
Szkielet metody
Składnia tworzenia metody jest następująca:
typ_zwracany nazwa_metody (lista parametrów)
{
//blok kodu który wykona się przy metodzie
}
typ_zwracany: tutaj określamy typ zwracany przez metodę. Typ, czyli przykładowo “int”, “string” i tak dalej. Jeśli metoda ma nie zwracać żadnej wartości korzystamy ze słowa kluczowego void.
nazwa_metody: Samo wyjaśnienie . Obowiązują tu te same zasady co do nazewnictwa zmiennych.
lista parametrów:Metoda nie musi koniecznie jej posiadać. Lista parametrów zawiera w sumie informacje, jakie zmienne muszą być przesłane do metody by wykonać daną operacje. Te parametry istnieją wewnątrz metody. Każdy parametr musi być oddzielony przecinkiem.
//blok kodu:Kod, który się wykona przy wywoływaniu metody. Jeśli metoda musi zwracać wartość to w tym bloku powinno być zawarte słowo kluczowe return wraz z daną zwracaną.
C# nie wspiera metod globalnych w przeciwieństwie do C i C++. Metody muszą być zadeklarowane wewnątrz klas.
Oto przykład metody odejmującej, która zwraca wynik działania bazując na podanych dwóch zmiennych.
int Odejmowanie(int x1,int x2)
{
return x1 - x2;
}
W przykładzie metoda nie zwraca żadnej wartość, ale wyświetla wynik działania za pomocą MessageBox.
void Odjemowanie(int x1,int x2)
{
MessageBox.Show((x1 - x2).ToString());
}
Małe wyjaśnienie słowa kluczowego return. W metodzie zwracające, jeśli zmienna została już zwrócona reszta kodu się nie wykona.
string Zwracam()
{
return "LOL";
string s = "Do tego program nigdy nie dojdzie";
}
Teraz gdy wiesz jak napisać metodę. Zobaczymy jak ją wywołać.
Wywoływanie metody
Wywoływanie metody wygląda w ten sposób.
WykonamOperacje();
int rezultat = ObliczeCos(1,2);
Aby wywołać metodę trzeba pamiętać o następujących zasadach:
- Musisz podać odpowiednią listę argumentów, jaką metoda potrzebuje.
- Argumenty muszą być tego samego typu, jakiego są potrzebne do metody.
- Musisz odwołać się do niej poprzez dokładną jej nazwę.Wielkość liter ma znaczenie
- Pamiętaj czy metoda zwraca wartość. Jeśli zwraca wartość, to trzeba ją przechwycić poprzez zmienne pomocnicze.
- Nawet jeśli metoda nie ma żadnej listy argumentów to i tak trzeba napisać () by ją wywołać.
Aby wszystko było jasne oto przykłady:
void MessageNumber(string komunikat,int liczba)
{
MessageBox.Show(komunikat +" : " +liczba.ToString());
}
…oraz użycie tej metody.
MessageNumber(); //Za mało argumentów
MessageNumber("Liczba x")//Brakuje argumentu
MessageNumber(1, 2); //Zły typ argumentu
MessageNumber(5,"Cos");//Zła kolejność
MessageNumber("Liczba",1212);//Poprawne użycie
Wypadałoby wspomnieć o różnicy pomiędzy użyciem metody w programie Konsolowym , a WPF.
Statyczna metoda VS Niestatyczna metoda
Zanim jednak spróbujesz użyć metod w aplikacji konsolowej bądź WPF wypadałoby wspomnieć o drobnej różnicy przy ich w używaniu.
W konsolowej aplikacji metody wewnątrz klasy "Program" muszą być statyczne, by można było ich użyć wewnątrz metody “Main”. Wynika to z tego , że w aplikacji konsolowej nasze akcje są wyświetlana za pomocą metody Main, która jest statyczna. Wewnątrz statycznej metody można wywołać tylko kolejną statyczną metodę.
namespace ConsoleApplication2
{
class Program {
static void Main(string[] args)
{
int a = Mnozenie(2, 3);
Console.WriteLine(a);
Console.ReadKey();
}
static int Mnozenie(int x1, int x2)
{
return x1 * x2;
}
}
}
Metoda napisana w aplikacji WPF nie musi być statyczna. W tym przykładzie metoda uruchomi się jeszcze przed zobaczeniem okna głównego aplikacji, ponieważ kod jej wywołania jest w konstruktorze klasy MainWindow.
namespace WpfApplication1
{
public partial class MainWindow : Window {
public MainWindow()
{
InitializeComponent();
Odjemowanie(2, 3);
}
void Odjemowanie(int x1,int x2)
{
MessageBox.Show((x1 - x2).ToString());
}
}
}
Jaka jest różnica pomiędzy metodą statyczną a metodą niestatyczną? Aby to zobrazować musiałbym wyjaśnić, czym jest klasa i w jakich wypadkach może mieć ona metodę statyczną , a kiedy zwyczajną. Na razie nie będzie to jednak potrzebne.
Przeciążanie metod
Jak wcześniej zaznaczyłem metoda “Console.Wrtiteline()” jest metodą przeciążoną i ma aż 19 wersji z różnymi parametrami. Dzięki temu ta metoda może wyświetlić nam w konsoli parametry liczbowe albo nawet logiczne. Czyli robi dokładnie to samo, mimo iż podaje do niej inne parametry.
bool t = true;
int l = 121;
Console.WriteLine(t);
Console.WriteLine(l);
Jak stworzyć przeciążoną metodę. Jeśli dwa identyfikatory mają takie same nazwy stają się one przeciążone. Normalnie, gdy zadeklarujemy dwie zmienne o te samej nazwie, kompilator zgłosi nam błąd. Jednak dla metody o tej samej nazwie, ale z różnymi parametrami już nie.
Pisząc dwie wersje metody z różną listą parametrów tworzymy dwie możliwości ich użycia.
Jak widać na obrazku metoda “Mnozenie()” jest w dwóch wersjach. W jednej potrzebuje 2 parametrów w drugiej aż 3.
Nie ma tutaj dużej filozofii w ten sposób mogę utworzyć tyle wersji ile potrzebę.
Metody z opcjonalnymi parametrami
Właśnie zobaczyłeś jak działa przeciążanie metod. Kiedy aplikacja się skompiluje kompilator będzie wiedział z jakiej wersji skorzystać, bazując na podanych w metodzie parametrach.
Istnieje jeszcze jednak inny mechanizm przy tworzeniu metod. W niektórych sytuacjach jest on bardziej użyteczny niż przeciążanie metod. Polega to na utworzeniu metody z opcjonalnymi parametrami. Zalety takiego rozwiązania łatwo wykazać za pomocą prezentacji.
Załóżmy , że mam metodę dwa razy przeciążoną . Operacja wykonywana w metodzie “PracaPraca” , powiedzmy , że zapisuje liczbę dni, godzin i minut do źródła danych.
void PracaPraca(int liczbaDni,int liczbaGodzin,int liczbaMinut)
{ }
void PracaPraca(int liczbaGodzin, int liczbaMinut)
{ }
Jak na razie nie ma tu żadnego problemu. Ale co się stanie, jeśli zechcę stworzyć metody dwa razy przeciążone, które pobierają tylko jeden parametr np. w jedna wersji metoda będzie potrzebowała tylko liczbę dni , a w drugiej tylko liczbę godzin.
void PracaPraca(int liczbaDni)
{ }
void PracaPraca(int liczbaGodzin)
{ }
Kompilator w takim wypadku zgłosi błąd.
Taki kod nie przejdzie przez kompilator z prostego powodu. Kompilator i program nie wie, z której metody będziesz korzystał, jeśli obie potrzebują jednej zmiennej tego samego typu.
int liczbaDni = 2;
int liczbaGodzin = 18;
PracaPraca(liczbaDni);
//koleś czego chcesz której metody mam użyć
PracaPraca(liczbaGodzin);
//koleś czego chcesz której metody mam użyć
Do takiej sytuacji mamy parametry opcjonalne. Do zrozumienia jak opcjonalne parametry działają muszę pokazać dwie rzeczy:
- Jak można w C# zadeklarować zmienne opcjonalne.
- Jak można w C# wywołać metodę podając parametry w innej kolejności
Deklaracja metody z opcjonalnymi parametrami
W metodzie można przypisać parametrom stałe wartości.
static void PracaPraca(int liczbaDni = 0,int liczbaGodzin = 0,
int liczbaMinut = 0)
{ }
Jedyną zasadą dotyczącą opcjonalnych parametrów jest fakt, że wszystkie zmienne, które nie mają wartości domyślnych muszą być najpierw zadeklarowane.
Visual Studio zaznacza , że parametry mają domyśle wartości.
Jednak zapewne zauważyłeś, że istnieje problem z umieszczaniem właściwej kolejności parametrów. Jak można podać tylko liczbę godzin?.
Inna kolejność parametrów
Domyślnie w C# kolejność parametrów musi być podawana od lewej do prawej . Jednak da się to rozwiązać poprzez odwołanie się do nich za pomocą ich nazw.
PracaPraca(liczbaGodzin: 18);
PracaPraca(liczbaMinut:45,liczbaDni:1)
Nawet Visual Studio pomaga w tym procesie ,więc nie musisz pamiętać nazw zmiennych do metody.
Prawda , że to proste.
Skomplikujmy jednak teraz sprawę i stwórzmy metodę dwa razy przeciążoną z parametrami opcjonalnymi i nieopcjonalnymi.
Łączenie metody przeciążonej z parametrami opcjonalnymi. Problemy z kompilacją?
Metoda przeciążona z różnymi typami parametrów wygląda następująco.
static void PracaPraca(bool zadanieWykonane,
int liczbaDni = 0,int liczbaGodzin = 0)
{ }
static void PracaPraca(bool zadanieWykonane,
int liczbaDni = 0, int liczbaGodzin = 0, int liczbaMinut = 0)
{ }
Łącząc technikę przeciążania metod z parametrami opcjonalnymi wymaga przestrzegania pewnych zasadach. Spójrzmy na poniższy kod.
PracaPraca(true, 1, 8);//pierwsza wersja
PracaPraca(true,liczbaMinut:12);//druga wersja
PracaPraca(true, 2);//wywołuje błąd
PracaPraca(true, liczbaGodzin: 12);
//tutaj też kompilator nie wie z której wersji skorzystać
PracaPraca(true);//to samo
Z pierwszym zapisem kompilator nie ma problemów, ponieważ wszystkie parametry potrzebne do wersji pierwszej zostały podane.
Z drugim zapisem kompilator też nie ma problemów, ponieważ wie ,że zmienna reprezentująca liczbę minut istnieje tylko w drugiej wersji.
Z trzecim zapisem kompilator ma już problem, mając podany parametr - liczbę dni, nie jest on w stanie stwierdzić, z której wersji ma skorzystać, ponieważ obie wersje mają ten sam parametr opcjonalny. Podobny problem występuje w zapisie 4, jak i 5.
W następnym odcinku
Opisze warunki if oraz wyrażenia logiczne w C#.