SlideShare a Scribd company logo
1 of 104
.net
xml
JSP
SOAP
HTTP
CSSFTPJavaScript
Kolekcje klas
Różnice pomiędzy tablicami a kolekcjami:
• Tablica deklaruje typ elementów, które przechowuje. Kolekcja
tego nie robi ponieważ kolekcja przechowuje elementy jako
obiekty.
• Tablica ma określony rozmiar i nie można jej powiększyd ani
zmniejszyd. Kolekcja w zależności od potrzebny dynamicznie
dostosowuje automatycznie rozmiar.
• Tablica może byd wielowymiarowa. Kolekcja nie może byd
wielowymiarowa. Jednak kolekcje mogą przechowywad
wewnątrz siebie inne kolekcje.
Kolekcja ArrayList
• ArrayList można traktowad jak ulepszenie tablicy. Jeśli irytowały cię
pewne wady tablicy, to ta klasa większośd ich rozwiąże . Potrafi ona:
Usuwad wybrane elementy z kolekcji przy użyciu metody Remove().
Elementy automatycznie ustawią się w wybrane miejsca.
– Za pomocą metody RemoveAt() usuwa się dany element przy
pomocy jego indeksu.
– Dodawad kolejne nowe elementy za pomocą metody Add(). W
razie potrzeby ArrayList automatycznie zmieni swój rozmiar.
– Dodawad elementy w środku zbioru elementów za pomocą
metody "Insert().
– Może odnieśd referencyjnie do istniejącego elementu w
ArrayList za pomocą nawiasów kwadratowych i numery indeksu
elementu.
ArrayList liczby = new ArrayList();
//przykład meotdy Add
for (int i = 0; i < 10; i++)
{
liczby.Add(i);
}
//Przykład metody Remove()
int usuneL = 1;
liczby.Remove(usuneL);
//Przykład metody RemoveAt()
liczby.RemoveAt(7);
//Przykład Insert()
int dodamL = 121; l
iczby.Insert(3, dodamL);
• Jak widzisz kasowanie i dodawanie elementów nie stworzyło
bałaganu w ArrayList.
• ArrayList posiada jeszcze wiele innych fajnych możliwości, jak
kasowanie elementów od - do za pomocą RemoveRange().
Wyszukiwanie indeksu wybranego elementu za pomocą
IndexOf().
• Czy czyszczenie zawartości za pomocą metody Clear(). oraz
możliwośd kopiowania zawartości do tablicy obiektów za
pomocą metody ToArray(). Muszą to byd obiekty ponieważ
ArrayList tak przechowuje elementy bez określenia ich typów.
Czyli ArrayList może przechowywad wiele różnych elementów.
int poszukiwany = 9;
int indeks = liczby.IndexOf(poszukiwany);
liczby.RemoveRange(0, 4);
object[] tablicaObiektów = liczby.ToArray();
liczby.Clear();
int wielkosc = liczby.Count;
DEMO
Kolekcje generyczne
Kolekcje
• Typ “object” referuje się do wartości o jakimkolwiek typie. Wszystkie typy
referencyjne dziedziczą automatycznie po klasie System.Object także
wbudowane klasy w .NET .
• Daje to możliwośd tworzenia metod czy zmiennych, które mogą przechowywad
różne wartości. Klasy takie jak ArrayList, HashTable są kolekcjami, które mogą
przechowywad wszystko. Opisałem je w tym wpisie.
• Możesz tworzyd kolejki, stosy, które mogą zawierad w sobie każdy typ. Problem
polega na tym, że skoro te kolekcje mogą przechowywad wszystko to mogą w
nich znaleźd się nieodpowiednie obiekty. Co prawda mamy do dyspozycji słowa
kluczowe jak “as” czy “is” , które mogą sprawdzad czym tak naprawdę jest dany
“object” , ale wciąż nie zmienia to faktu, że jest to uciążliwe.
• Kolejną poważną wadą tego zastosowania jest pakowanie i wypakowywanie
danych. Umieszczając np. liczbę do ArrayList musi byd ona spakowana do
obiektu , a gdy chcemy ją wyciągnąd musi byd ona wypakowywana.
int zlo = 42;
ArrayList al = new ArrayList();
al.Add(zlo);
//pakowanie
zlo = (int)al[0] + 1;
//wypakowywanie
int zlo = 42;
Queue kolejka = new Queue();
kolejka.Enqueue(zlo);
//wrzucanie do kolejki
zlo = (int)kolejka.Dequeue();
//wyciąganie z kolejki
DYRASTYCZNY PRZYKŁAD
class Kobieta
{
public void Zabawa(FacetJohnyBrawo facet)
{
Console.WriteLine("Dobrze się bawiłam");
}
}
class FacetJohnyBrawo
{
ArrayList mojekobiety = new ArrayList();
public void DodajKobiete(Kobieta kobieta)
{
mojekobiety.Add(kobieta);
}
public void IdzNaRandkePoKoleji()
{
foreach (var kobieta in mojekobiety)
{
Console.WriteLine(kobieta);
}
}
}
FacetJohnyBrawo johnyBravo = new FacetJohnyBrawo();
johnyBravo.DodajKobiete(new Kobieta());
johnyBravo.DodajKobiete(new Kobieta());
johnyBravo.DodajKobiete(new Kobieta());
johnyBravo.DodajKobiete(new Kobieta());
johnyBravo.IdzNaRandkePoKoleji();
class FacetJohnyBrawo
{
List<Kobieta> mojekobiety = new List<Kobieta>();
public void DodajKobiete(Kobieta kobieta)
{
mojekobiety.Add(kobieta);
}
public void IdzNaRandkePoKoleji()
{
foreach (var kobieta in mojekobiety)
{
kobieta.Zabawa(this);
}
}
}
O CO CHODZI
int dobro = 0;
Queue<int> kolejka = new Queue<int>();
kolejka.Enqueue(dobro);
dobro = kolejka.Dequeue();
public class Queue<T> : //...public class Stack<T> : //...
public void Enqueue(T item);
public T Dequeue();
T
• Parametr T zastępuje dany typ i jest zastąpiony prawdziwym typem
w czasie deklaracji danej klasy Generics.
• Do tych klas nie można więc już umieścid innych typów od
tych, które zadeklarowaliśmy zamiast <T>.
• Mechanizm T jest bardziej skomplikowany niż się wydaje. Jego
działanie nie polega dosłownie na zastąpieniu tego elementu jakby
kod to był jakiś notatnik, czy word. Kompilator dokonuje dokładną i
kompletną substytucje w taki sposób ,aby T mogło referowad się do
każdego typu.
• Jednak przykładowo Queue<string> i Queue<int> powinny byd
traktowane jak dwa oddzielne typy danych. Specyficzne typy klas
Generics nazywane są zbudowanymi typami “constructed types” .
DEMO
Delegaty
Wstęp
• W WPF mamy do dyspozycji kontrolki , jak przyciski czy
textbox-y. Kiedy klikasz na przycisk, czy piszesz jakiś tekst
oczekujesz , że dane zdarzenie wykona się natychmiastowo. W
rzeczywistości tak nie jest.
• Aplikacja musi się na chwile zatrzymad i odpowiednio
przekierowad działania użytkownika. Nie dotycz to tylko
aplikacji z interfejsem użytkownika (UI) ,ale do każdej innej
aplikacji, w której czynnośd X musi byd wykonana
natychmiastowo bez względu na inne procesy w tle.
• Delegata jest wskaźnikiem do danej
metody. Poprzez daną delegate możesz
wywoład daną metodę. Kiedy wywołujesz
daną delegatę program tak naprawdę
wykonuje daną metodę, do której
delegata się referowała.
C++
Jeśli znasz język programowania taki jak C++
to zapewne zdałeś sobie już sprawę , że
delegata działa podobnie do wskaźnika
funkcji. Jednak delegaty są
bezpieczniejsze, dana delegata może tylko
referowad się do metody, której sygnatura
jest zgodna z delegatą. Nie możesz wywoład
delegaty, która nie referuje się do właściwiej
dla siebie metody
Problem ze zrozumieniem
• Znając życie, ponieważ sam miałem z tym problem, na pewno
się teraz zastanawiasz, po co w ogóle są delegaty?
• Jeśli chcę wywoład metodę X to ją wywołuję po co mi
delegata, która robi dokładnie to samo tylko
pozwala wywoład metodę pod inną nazwą.
• Czas na przykład.
Sytuacja
• Mamy dziecko i oboje rodziców. Dziecko płacze i trzeba je
przewinąd. Ponieważ matka jest zajęta deleguje to
zadanie ojcu.
• A ojciec ma w swojej klasie metodę, którą zadnie to może
wykonad.
• Bez delegat przykład wygląda tak.
class Dziecko
{
private bool glodny;//tak rodzice nie wiedzą co chce dziecko :)
private Mama mama;
private Tata tata;
public void MozeChceJesc()
{
if (glodny == false)
{
Console.WriteLine("Dziecko nie jest głodne");
}
else
{
if (mama.zmęczona == false)
{
mama.Nakarmienie(this);
}
else
{
tata.Nakarmienie(this);
} glodny = false;
}
}
//a ty myślałeś ,że dzieci biorą się z pszczółek i kwiatków
public Dziecko(Mama duzaCieplaPlama, Tata duzaZnajomaPlama)
{
//z puntu nowonarodzonego dziecka wszystko jest jedną fajną plamą
mama = duzaCieplaPlama;
tata = duzaZnajomaPlama;
}
}
Opis cz1
• Zakładamy ,że wszystkie obowiązki wykonuje
zawsze mama ,ale jeśli jest ona zmęczona to
obowiązek przechodzi na ojca ,a ojciec nie
może byd zmęczony.
• Ponieważ rodzice nie wiedzą, co dziecko chce
, jego pola jak “głodny” są prywatne i nie mają
właściwości przypisanych do nich.
Opis cz2
• Istnieje jednak dużo większy problem.
• Te rozwiązanie nie jest elastyczne. Gdyby nagle
się okazało się, że babcia i dziadek też mogą
zajmowad się tymi obowiązkami musiałbym
dodad ich do klasy Dziecko.
• Jednym słowem obecne rozwiązane jest
stworzone do jednego konkretnego rozwiązania.
Co należy zrobić
• Tę logikę wypadało jakoś oddzielid od klasy
dziecko. Dlatego stworzenie abstrakcyjnej klasy
bazowej “OpiekunDziecka” też tutaj do kooca nie
rozwiąże sprawy.
• W programowaniu nie jest to sympatycznie
odbierane zwłaszcza jeśli programista spodziewa
się , że ten kod może ulec zmianie. W pracach
domowych na studiach możesz sobie na to
pozwolid ale nie w życiu.
UŻYWANIE DELEGAT
Co należy zrobić
• Mimo, iż metody mają różne nazwy i mogą
pochodzid od różnych klas wszystkie muszą
mied podobny “kształt”.
• W tym przykładzie każda z metod przyjmuje
parametr klasy Dziecko i nie zwraca żadnej
wartości. Format wszystkich tych metod
będzie następujący.
void Nazwa(Dziecko dziecko)
delegate void MozeChceJescDelgata(Dziecko dziecko);
• Na co trzeba zwrócid uwagę:
Użycie słowa kluczowego “delegate” przy
deklaracji delegaty
• Delegata definiuje kształty metody, do które
się referuje. Metoda nie może niczego zwracad
“void” i musi przyjmowad jeden parametr
“dziecko”.
Po stworzeniu delegaty możesz stworzyd jej instancje.
Przy użyciu operatora += możesz przypisad do niego odpowiednią metodę.
Zrobię to w konstruktorze klasy Dziecko ,aby nie wnikad na razie w szczegóły
sytuacyjne. Mam przecież wyjaśnid jak działają delegaty.
class Dziecko
{
delegate void mozeChceJescDelgata(Dziecko dziecko);
private mozeChceJescDelgata mozeChceJesc;
// instancja delegaty
public Dziecko(Mama mama)
{
this.mozeChceJesc += mama.Nakarmienie;
}
}
Dodanie metod do delegat
• Dodajesz metodę do delegaty w tym momencie metoda nie
jest wywoływana.
• Operator „=+” dla delegaty jest nadpisany i ma swoje unikalne
zastosowanie. Zauważ też , że do metody nie dodałem
żadnego parametru i nie ma nawet nawiasów ().
• Istnieje jeszcze inny sposób na przypisanie delegaty do
odpowiedniej metody jednak wyrażenie += jest
bezpieczniejsze w użyciu oraz inicjacja przebiegnie
automatycznie. Ten inny sposób wygląda tak.
this.mozeChceJesc = new mozeChceJescDelgata(mama.Nakarmienie);
• Jak widzisz ilośd kodu jest trochę większa ale w
ten sposób instancja delegaty będzie zawsze
odwoływad się do jednej metody.
• Używając znaku += tak naprawdę dodajesz
następne możliwe metody, które mają się
wykonad
Uwaga
• Wywołanie delgaty, która nie jest
zainicjowana oraz nie ma przypisanej
żadnej metody grozi wyrzuceniem
wyjątku “NullReferenceException”.
Przykład CDN
• Tak jak powiedziałem wcześniej używając wyrażenia +=
skutkuje przypisaniem kolejnej metody do danej delegaty. Jest
to zwykle zaleta niż wada. Dlaczego?
• Otóż wyobraź sobie taką sytuacje. Skoro rodzice nie
wiedzą, co chce dziecko, to najczęściej wykonują wszystkie
operacje po kolei. Przynajmniej tak to wygląda z
programistycznego punktu widzenia ponieważ obiekty mama i
tata nie posiadają sztucznej inteligencji aby zgadywad
precyzyjnie co chce dziecko xD.
class Dziecko
{
delegate void cosChceDelgata(Dziecko dziecko);
private cosChceDelgata cosChce;
// instancja delegaty
public Dziecko(Mama mama)
{
this.cosChce += mama.Przewiniecie;
this.cosChce += mama.Nakarmienie;
this.cosChce += mama.Ululanie;
}
public void CosChceMetoda()
{
this.cosChce(this);
}
}
Dziecko Rosesmary = new Dziecko(new Mama());
Rosesmary.CosChce();
Mocna strona delegat
• To bardzo mocna strona delegaty wszystkie metody wykonały
się i to w określonej kolejności. W koocu wolałbym przypisad
100 metod do jednej delegaty, niż pisad 100 linijek za każdym
razem, gdy chcę wykonywad te operacje.
• Delegaty też dają pewną elastycznośd bo przecież kolejnośd
działao była zadeklarowana w konstruktorze, a nie
bezpośrednio w kodzie jakbym pisał metoda po metodzie.
Możesz też usuwad metody za pomocą
operatora –=.
this.cosChce -= mama.Nakarmienie;
Publiczne Delegaty
• Obecnie opiekunowie dziecka byliby
dodawani w konstruktorze ponieważ
obecnie instancja delegaty jest prywatna.
• Warto ją zmienid na publiczną w ten
sposób klasa dziecko powinna byd
niezależna od swoich opiekunów
public cosChceDelgata cosChce;
// instancja delegaty
delegate void cosChceDelgata(Dziecko dziecko);
private cosChceDelgata _cosChce;
// instancja delegaty
public cosChceDelgata CosChce
{
get { return cosChce; }
set { cosChce = value; }
}
Heremtyzacja dziecka
• Można też zaszaled i dad klasie Dziecko pełne
hermetyczne rozwiązanie zakładając nawet
, że dziecko nie wie co rodzice będą robid by
zaspokoid jego potrzeby.
• Biedny dzieciak nawet nie wie, co mu dolega i
kiedy to przechodzi. Zasada hermetyzacji jest
taka brutalna.
public delegate void cosChceDelgata(Dziecko dziecko);
private cosChceDelgata cosChce;
// instancja delegaty
public void Dodaj(cosChceDelgata MetodaX)
{
this.cosChce += MetodaX;
}
public void Usun(cosChceDelgata MetodX)
{
this.cosChce -= MetodX;
}
Wyrażenia Lambda
class MaszynaPracujaca
{
public void UruchomMaszyne()
{
Console.WriteLine("Maszyna Uruchomiona");
}
public void ObliczWzorZimnejFuzji()
{
Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G");
}
public void OdnajdzSensZycia()
{
Console.WriteLine("42");
}
public void WylaczMaszyne(int czasZamkniecta)
{
Console.WriteLine("Zamkniecie za {0}", czasZamkniecta);
}
}
class MaszynaZadan
{
public delegate void listZadanDelegata();
private listZadanDelegata listaZadan;
public MaszynaZadan(MaszynaPracujaca maszyna)
{
listaZadan += maszyna.UruchomMaszyne;
listaZadan += maszyna.ObliczWzorZimnejFuzji;
listaZadan += maszyna.OdnajdzSensZycia;
}
public void RozpocznijZadania()
{
listaZadan();
}
}
MaszynaZadan mz = new MaszynaZadan(new MaszynaPracujaca());
mz.RozpocznijZadania();
Jak dobrze pamiętasz mówiłem też coś o zasadzie hermetyzacji czyli klasa
MaszynaZadan jest chwilowo źle napisana ponieważ jej działanie jest zależne od klasy
MaszynaPracująca.
Problem ten można rozwiązad w następujący sposób. Sprawiając , że klasa
MaszynaZadan może byd elastycznie dostosowywana.
class MaszynaZadan
{
public delegate void listZadanDelegata();
private listZadanDelegata listaZadan;
public void Dodaj(listZadanDelegata MetodaX)
{
listaZadan += MetodaX;
}
public void Usun(listZadanDelegata MetodX)
{
listaZadan -= MetodX;
}
public void RozpocznijZadania()
{
if (listaZadan != null)
listaZadan();
}
}
ADAPTERY
Może nie zauważałeś ,ale w klasie MaszynaPracująca jest metoda
“WylaczMaszyne”.
class MaszynaPracujaca
{
public void UruchomMaszyne()
{
Console.WriteLine("Maszyna Uruchomiona");
}
public void ObliczWzorZimnejFuzji()
{
Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G");
}
public void OdnajdzSensZycia()
{
Console.WriteLine("42");
}
public void WylaczMaszyne(int czasZamkniecta)
{
Console.WriteLine("Zamkniecie za {0}", czasZamkniecta);
}
}
Metoda ta przyjmuje parametr int czyli jej kształt bądź jak wolisz sygnatura jest inna
niż innych metod tej klasy. Ten kształt jest nie zgodny z sygnaturą delegaty, która
przyjmuje tylko metody bezparametrowe.
class MaszynaPracujaca
{
public void UruchomMaszyne()
{
Console.WriteLine("Maszyna Uruchomiona");
}
public void ObliczWzorZimnejFuzji()
{
Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G");
}
public void OdnajdzSensZycia()
{
Console.WriteLine("42");
}
public void WylaczMaszyne(int czasZamkniecta)
{
Console.WriteLine("Zamkniecie za {0}", czasZamkniecta);
}
public void NatchmiastoweWylaczenie()
{
this.WylaczMaszyne(0);
}
}
mz.Dodaj(mp.NatchmiastoweWylaczenie);
//dla klasy która jest w wersji konstruktora
listaZadan += maszyna.NatchmiastoweWylaczenie;
Wyrażenie Lambda
• Oczywiście pojawiło się pytanie gdzie ta metoda adaptująca
powinna byd. Oczywiście jest ona w klasie
“MaszynaPracująca” stąd to słowo kluczowe “this” jako
wskazówka. Jednak co jeśli nie możemy zmienid zawartości tej
klasy.
• Nawet jeśli możemy zmienid zawartośd tej klasy, to co jeśli ta
klasa jest gigantyczna.
• Tak czy siak, ta metoda istnieje tylko z powodu jednej delegaty
i raczej na pewno nie będzie używana nigdzie indziej.
• W C# do takich przypadków lepiej zastosowad wyrażenie
lambda czyli naszą gwiazdę tego wykładu.
Wyrażenie Lambda
• Wyrażenie lambda zwraca metodę.
• Brzmi to fantastycznie chociaż na pewno możesz się
zastanawiad jako to w ogóle działa. Zwykle wyrażenia w C#
zwracają jakąś wartośd “X”.
• W językach programowania funkcjonalnego jest to dośd często
spotykane zachowanie. Wraz z C# 3.0 pojawiły się wyrażenia
lambda (jak i zapytania LINQ) i od tamtej pory twój kod
miejscami może przypominad język funkcjonalny.
Programowanie funcjonalne
• Oto mała informacja z Wikipedii z nagłówka “Functional
programming in non-functional languages”w wpise o językach
programowania funkcjonalnego. Jak widzisz pewne trendy
przechodzą nawet na języki programowania, które nie są
funkcjonale i nie mówi się tu tylko o C#. Doszło to nawet do
języka PHP, he…no tego bym się nie spodziewał. Kiedyś nie był
to obiektowy język.
• Z tego co kiedyś czytałem w kolejnej wersji języka Java też
mają pojawid się te wyrażenia.Wyrażenia lambda są nawet
obecne we wzorcach projektowych.
Tworzenie metod
• Koniec jednak tej lektury. Wyrażenie lambda nie jest takie
skomplikowane. To tylko kolejny zestaw znaków, które trzeba
zapamiętad i tyle. Zresztą jest ono bardzo użyteczne , a więc
okazja użycia pojawi się jeszcze nie raz.
• Typowa metoda musi składad się z 4 elementów:
– Nazwy
– Listy parametrów
– Ciała metody
– Zwracanej wartości
Wyrażenie Lambda
• Wyrażenie lambda zawiera tylko dwa elementy: listę
parametrów oraz ciało metody.
• Wyrażenia Lambda nie określają swojej nazwy.
• Wyrażenie lambda nie definiuje też zwrotnego parametru.
Jednak jakiś parametr może byd zwracany jeśli wynika to z
zawartości jej ciała.
• Wracając do problemu z metodą “WyłaczMaszyne(int
czasZamkniecia)” .
• Musimy stworzyd adapter metody WylaczMaszyne w taki
sposób ,aby nie miała ona żadnych parametrów i mogłaby byd
dodana do instancji delegaty “ListaZadan”.
mz.Dodaj( (() => { mp.WylaczMaszyne(0);}) );
//dla klasy która jest w wersji konstruktora
listaZadan += (() => { maszyna.WylaczMaszyne(0); });
WYRAŻENIE LAMBDA CHCE
WIĘCEJ…WIĘCEJ FORM
DEMO
Lambda podsumowanie
• Czas na podsumowanie tego kodu i to nie za pomocą
zielonego komentarza w kodzie.
Wyrażenia lambda mogą zwracad wartości jednak muszą one
pasowad do typu danej delegaty, do której są dodawane.
• Ciało wyrażenia lambda może byd prostym wyrażeniem albo
blokiem kodu C# z wieloma stwierdzeniami, wezwaniami
innych metod, definicją zmiennych i innych rzeczy.
• Zmienne zdefiniowane wewnątrz wyrażenia lambda istnieją
tylko w tym bloku kodu i znikają gdy metoda się skooczy,
Lambda podsumowanie
• Wyrażenie lambda ma dostęp do wszystkich zmiennych i metod
znajdujących się po za tym wyrażeniem. W czasie wykonywania
wyrażenia zmienne ulegają zmianie tymczasowo. Warto o tym
pamiętad.
• Jeśli wyrażenie lambda pobiera jakieś parametry możesz nie
podawad ich typów ponieważ kompilator skojarzy je z kontekstu
danego wyrażenia. Jednak przy słowach kluczowych jak ref i out
musisz też podad ich typ.
• Wyrażenie lambda może zmienid wartości na zawsze jeśli są one
przesłane do metody za pomocą słów kluczowych ref i out.
METODY ANONIMOWE
Metody Anonimowe
• W C# 2.0 czyli przed wyrażeniami lambda były metody
anonimowe, które spełniały podobny cel do wyrażeo lambda
ale nie były tak elastyczne.
• Anonimowe metody zostały dodane po to aby dad
programistom możliwośd definiowania delegat bez określenia
ich nazw. Metody te zawierały w sobie tylko swoją definicję.
listaZadan += delegate { maszyna.WylaczMaszyne(0); };
mz.Dodaj(delegate { mp.WylaczMaszyne(0); });
Aby stworzyd metodę anonimową musisz użyd słowa
kluczowego delegate.
Parametry też muszą byd określone w nawiasach przy słowie
kluczowym delegate.
operacjeMatDwuArg += delegate(int x, int y) { return x - y; };
Metody Anonimowe
• Zostały jednak one osunięte w cieo. Złożone zadania
wyglądają o wiele lepiej w wyrażeniu lambda dlatego też już
prawie nikt nie pamięta o tamtej formie zapisu. Chyba
,że ktoś z jakiegoś powodu musi programowad w C# 2.0.
• To taka ciekawostka ponieważ wyrażenia lambda są lepsze.
Może jednak kiedyś spotkasz się z takimi zapisami.
Piszemy zdarzenia
Wstęp
• Jednak to jeszcze nie koniec. Co prawda możesz wywoład wiele metod nie
bezpośrednio za pomocą delegaty, ale wciąż musisz ją wywoład jawnie. Z
programistycznego punktu widzenia dobrze byłoby , aby delegaty
uruchomiały się automatycznie gdy coś ważnego się wydarzy.
• Przykładowo, w przypadku przegrzewania się reaktora atomowego
wywoład odpowiednią delegate, która wykona wszystkie metody po
kolei w celu jego wyłączenia .
• W wielu wypadkach klasy znajdujące się w .NET pokazują użycie zdarzeo
(event). Zdarzenia są używane do zdefiniowania i przechwytywania
określonych akcji .Określają one też użycie odpowiedniej delegaty, która
sobie z daną sytuacją X poradzi.Większośd kontrolek z WPF ,Windows
Forms, Silverlight , a nawet z ASP.NET używa zdarzeo.
Nawet np. sama klasa okna głównego w WPF przechowuje następujące
zdarzenia.
Zdarzenia
• Zdarzenie może byd zadeklarowane tylko w klasie i to ona jest
zawsze źródłem tego zdarzenia.
Źródłem danego zdarzenia jest zazwyczaj klasa, która
monitoruje dane środowisko oraz wywołuje zdarzenie w
momencie spełnienia danego warunku.
• Niektóre klasy mają np. zdarzenia, które zostaną wywołane w
przypadku zajścia błędu. Idąc tym tropem przyszedł mi głowy
następujący przykład zastosowania zdarzenia.
• Mamy do dyspozycji klasę “PobieraczPlików” , której
zadaniem jest pobranie poprzez sied różnego rodzaju plików.
Zdarzenia
• Klasa ta ma dwa pola
– liczbeDoPobraniaPlików”, która będzie mówid nam ile
plików ma ta klasa pobrad.
– “liczbePobranychPlikow” , która będzie opisywad ile plików
zostało już pobranych.
• Zdarzenie “PrzyBledziePobierania” zajdzie jeśli klasa wykryje , że
dane pobieranie nie skooczyło się prawidłowo. Inne zdarzenie
“SkonczonePobieranie” zajdzie gdy liczba pobranych plików będzie
równa liczbie plików, którą planowaliśmy pobrad.
• Zdarzenia te będą przechowywad listę metod, które mają byd
wywoływane w czasie ich zajścia.
Te metody są nazywane subscribers , co dosłownie można
przetłumaczyd jako wyraz subskryptami. Jednak na pewno nie jest
to prawidłowe tłumaczenie (nie ma takiego słowa w języku
polskim). Metody te obsłużą nasze zdarzenie i wykonają
odpowiednie akcje np. przy “PrzyBledziePobierania” użytkownik
zostanie poinformowany , że dany plik nie mógł zostad pobrany.
event NazwaTypuDelegaty NazwaZdarzenia
class PobieraczPlikow
{
public delegate void BladPobierniaDelegata(string wiadomosc);
public delegate void SkonczonePobieranieDelegata();
private int liczbaPobranychPlikow;
private int liczbaDoPobraniaPlikow;
}
class PobieraczPlikow
{
public delegate void BladPobierniaDelegata(string wiadomosc);
public event BladPobierniaDelegata PrzyBlendziePobierania;
public delegate void SkonczonePobieranieDelegata();
public event SkonczonePobieranieDelegata SkonczonePobieranie;
private int liczbaPobranychPlikow;
private int liczbaDoPobraniaPlikow;
}
WYWOŁANIE ZDARZENIA
class PobieraczPlikow
{
public void WystapilBlad()
{
if (PrzyBlendziePobierania != null)
{
PrzyBlendziePobierania("Wystapił błąd");
}
Jak widzisz jeśli dana delegata w zdarzeniu definiuje jakieś
parametry muszą one byd podane w trakcie ich wywołania.
Zdarzenia też mają pewną istotną wbudowaną funkcje mogą one
byd wywołane wewnątrz klasy, która je definiuje w tym wypadku
wewnątrz klasy “PobieraczPlikow”. Próba wywołania zdarzenia
poza tą klasą skooczy się błędem w czasie kompilacji programu.
class PobieraczPlikow
{
//konstruktor
public PobieraczPlikow(int l)
{
liczbaDoPobraniaPlikow = l;
}
//proste wywołanie zdarzenia
public void WystapilBlad()
{
if (PrzyBlendziePobierania != null)
PrzyBlendziePobierania("Wystapił błąd");
}
public delegate void BladPobierniaDelegata(string wiadomosc);
public event BladPobierniaDelegata PrzyBlendziePobierania;
public delegate void SkonczonePobieranieDelegata();
public event SkonczonePobieranieDelegata SkonczonePobieranie;
private int liczbaPobranychPlikow;
public int LiczbaPobranychPlikow
{
get { return liczbaPobranychPlikow; }
set
{
if (value == liczbaDoPobraniaPlikow)
{
if (SkonczonePobieranie != null)
SkonczonePobieranie();
}
liczbaPobranychPlikow = value;
}
}
private int liczbaDoPobraniaPlikow;
public int LiczbaDoPobraniaPlikow
{
get { return liczbaDoPobraniaPlikow; }
}
}
ZDARZENIA W WPF
Zdarzenia w WPF
• Pisałem już wcześniej , że WPF, Silverlight, ASP.NET w swoich klasach i
kontrolkach używa zdarzeo do kontrolki nad graficznym interfejsem
użytkownika.
• Ucząc się którejś z tych technologii czasami spotkasz się ze zdarzeniami.
Nawet początkujący programiści z nich korzystają i nie wiedzą dokładnie jak
one działają ponieważ wymaga to poznania wielu zagadnieo jak np. delegaty.
• No cóż , dla uproszczenia nie będę w tym wpisie zagłębiad się jak zdarzenia są
skonstruowane w ASP.NET. Zobaczmy jak zdarzenia są zrobione w WPF
zwłaszcza , że WPF i Silverlight w tym wypadku powinni byd do siebie podobni.
• Kontrolka przycisku dziedziczy po klasie bazowej “ButtonBase”. Ma to sens
ponieważ w WPF są też inne przyciski od tego standardowego jak np.
ToggleButton.
public class Button : ButtonBase
• Przycisk dziedziczy po niej zdarzenie “Click” , który jest typem
delegaty “RoutedEventHandler”.
• Delegata ta spodziewa się dwóch parametrów: referencji do
obiektu, który spowodował wywołanie tego zdarzenia oraz
obiekt klasy “RoutedEventArgs” , który przechowuje różne
dodatkowe informacje na temat tego zdarzenia.
• Jest to pomysłowe ponieważ nie chciałbyś widzied całej linijki
parametrów za każdym razem gdy obsługujesz dane
zdarzenie.
public abstract class ButtonBase : ContentControl, ICommandSource
{
public event RoutedEventHandler Click;
// Summary:
// Raises the System.Windows.Controls.Primitives.ButtonBase.Click routed event.
protected virtual void OnClick();
Button
• Klasa ButtonBase posiada też metodę wirtualną dostępną tylko dla
klas pochodnych, która może wywoład bezpośrednio to zdarzenie.
• Klasa Button uruchamia to zdarzenie gdy klikniesz na przycisk .
Jednak co dokładnie się dzieje w momencie jego kliknięcia? Skąd
klasa to wie ? To wychodzi poza ramy tego wpisu.
• W WPF mamy XAML , a w nim najczęściej mówimy, która kontrolka
obsługuje jakie zdarzenie. Jest to wygodne ale warto sobie
uświadomid , że kod łączący naszą metodę np. ”Button_Click” z
wydarzeniem wciąż istnieje jest on tylko wygenerowany przez
kompilator. W sumie to dużo rzeczy w kompilatorze się dzieje aby
powiązad kod XAML z kodem w C#.
private void Button_Click(object sender, RoutedEventArgs e)
{
}
Button
• Zdarzenia w wielu kontrolkach działają według tego samego
wzoru. Sygnatura delegata w zdarzeniach w kontrolkach jest
prawie zawsze taka sama. Delegata mówi , że ta metoda nic
nie może zwracad “void” oraz pokazuje dwa parametry:
sender: Referencja do kontrolki, która wywołała dane
zdarzenie.
• e: Zbiór pomocniczych argumentów, które otrzymało dane
zdarzenie.
• Mając do dyspozycji argument “seneder” teraz nic nie stoi na
przeszkodzie aby dana metoda X obsługiwała zdarzenie Click
dla 100 przycisków skoro możesz sprawdzid, który z nich
wywołał to zdarzenie.
Koniec
Do zobaczenia
Do następnego wykładu
o LINQ

More Related Content

More from Cezary Walenciuk

Przyszłość c# 6.0 i nawet c# 7.0
Przyszłość c# 6.0 i nawet c# 7.0 Przyszłość c# 6.0 i nawet c# 7.0
Przyszłość c# 6.0 i nawet c# 7.0 Cezary Walenciuk
 
Do celu...ale motywacji brak
Do celu...ale motywacji brakDo celu...ale motywacji brak
Do celu...ale motywacji brakCezary Walenciuk
 
Programowanie na wiele platform mobilnych - 2012
Programowanie na wiele platform mobilnych - 2012Programowanie na wiele platform mobilnych - 2012
Programowanie na wiele platform mobilnych - 2012Cezary Walenciuk
 
Pierwszy program w c# cezary walencik
Pierwszy program w c# cezary walencikPierwszy program w c# cezary walencik
Pierwszy program w c# cezary walencikCezary Walenciuk
 
C# - Typy Referecyjne i typy wartościowe i wiele innych rzeczy
C# - Typy Referecyjne i typy wartościowe  i wiele innych rzeczyC# - Typy Referecyjne i typy wartościowe  i wiele innych rzeczy
C# - Typy Referecyjne i typy wartościowe i wiele innych rzeczyCezary Walenciuk
 
Jak dodać prezentacje power point do bloga__
Jak dodać prezentacje power point do bloga__Jak dodać prezentacje power point do bloga__
Jak dodać prezentacje power point do bloga__Cezary Walenciuk
 

More from Cezary Walenciuk (7)

Przyszłość c# 6.0 i nawet c# 7.0
Przyszłość c# 6.0 i nawet c# 7.0 Przyszłość c# 6.0 i nawet c# 7.0
Przyszłość c# 6.0 i nawet c# 7.0
 
Do celu...ale motywacji brak
Do celu...ale motywacji brakDo celu...ale motywacji brak
Do celu...ale motywacji brak
 
Programowanie na wiele platform mobilnych - 2012
Programowanie na wiele platform mobilnych - 2012Programowanie na wiele platform mobilnych - 2012
Programowanie na wiele platform mobilnych - 2012
 
Pierwszy program w c# cezary walencik
Pierwszy program w c# cezary walencikPierwszy program w c# cezary walencik
Pierwszy program w c# cezary walencik
 
C# - Typy Referecyjne i typy wartościowe i wiele innych rzeczy
C# - Typy Referecyjne i typy wartościowe  i wiele innych rzeczyC# - Typy Referecyjne i typy wartościowe  i wiele innych rzeczy
C# - Typy Referecyjne i typy wartościowe i wiele innych rzeczy
 
Pętle w c#
Pętle w c#Pętle w c#
Pętle w c#
 
Jak dodać prezentacje power point do bloga__
Jak dodać prezentacje power point do bloga__Jak dodać prezentacje power point do bloga__
Jak dodać prezentacje power point do bloga__
 

Delegaty i kolekcje

  • 2.
  • 3.
  • 4.
  • 5.
  • 7. Różnice pomiędzy tablicami a kolekcjami: • Tablica deklaruje typ elementów, które przechowuje. Kolekcja tego nie robi ponieważ kolekcja przechowuje elementy jako obiekty. • Tablica ma określony rozmiar i nie można jej powiększyd ani zmniejszyd. Kolekcja w zależności od potrzebny dynamicznie dostosowuje automatycznie rozmiar. • Tablica może byd wielowymiarowa. Kolekcja nie może byd wielowymiarowa. Jednak kolekcje mogą przechowywad wewnątrz siebie inne kolekcje.
  • 8. Kolekcja ArrayList • ArrayList można traktowad jak ulepszenie tablicy. Jeśli irytowały cię pewne wady tablicy, to ta klasa większośd ich rozwiąże . Potrafi ona: Usuwad wybrane elementy z kolekcji przy użyciu metody Remove(). Elementy automatycznie ustawią się w wybrane miejsca. – Za pomocą metody RemoveAt() usuwa się dany element przy pomocy jego indeksu. – Dodawad kolejne nowe elementy za pomocą metody Add(). W razie potrzeby ArrayList automatycznie zmieni swój rozmiar. – Dodawad elementy w środku zbioru elementów za pomocą metody "Insert(). – Może odnieśd referencyjnie do istniejącego elementu w ArrayList za pomocą nawiasów kwadratowych i numery indeksu elementu.
  • 9. ArrayList liczby = new ArrayList(); //przykład meotdy Add for (int i = 0; i < 10; i++) { liczby.Add(i); } //Przykład metody Remove() int usuneL = 1; liczby.Remove(usuneL); //Przykład metody RemoveAt() liczby.RemoveAt(7); //Przykład Insert() int dodamL = 121; l iczby.Insert(3, dodamL);
  • 10. • Jak widzisz kasowanie i dodawanie elementów nie stworzyło bałaganu w ArrayList. • ArrayList posiada jeszcze wiele innych fajnych możliwości, jak kasowanie elementów od - do za pomocą RemoveRange(). Wyszukiwanie indeksu wybranego elementu za pomocą IndexOf(). • Czy czyszczenie zawartości za pomocą metody Clear(). oraz możliwośd kopiowania zawartości do tablicy obiektów za pomocą metody ToArray(). Muszą to byd obiekty ponieważ ArrayList tak przechowuje elementy bez określenia ich typów. Czyli ArrayList może przechowywad wiele różnych elementów.
  • 11. int poszukiwany = 9; int indeks = liczby.IndexOf(poszukiwany); liczby.RemoveRange(0, 4); object[] tablicaObiektów = liczby.ToArray(); liczby.Clear(); int wielkosc = liczby.Count;
  • 12. DEMO
  • 14. Kolekcje • Typ “object” referuje się do wartości o jakimkolwiek typie. Wszystkie typy referencyjne dziedziczą automatycznie po klasie System.Object także wbudowane klasy w .NET . • Daje to możliwośd tworzenia metod czy zmiennych, które mogą przechowywad różne wartości. Klasy takie jak ArrayList, HashTable są kolekcjami, które mogą przechowywad wszystko. Opisałem je w tym wpisie. • Możesz tworzyd kolejki, stosy, które mogą zawierad w sobie każdy typ. Problem polega na tym, że skoro te kolekcje mogą przechowywad wszystko to mogą w nich znaleźd się nieodpowiednie obiekty. Co prawda mamy do dyspozycji słowa kluczowe jak “as” czy “is” , które mogą sprawdzad czym tak naprawdę jest dany “object” , ale wciąż nie zmienia to faktu, że jest to uciążliwe. • Kolejną poważną wadą tego zastosowania jest pakowanie i wypakowywanie danych. Umieszczając np. liczbę do ArrayList musi byd ona spakowana do obiektu , a gdy chcemy ją wyciągnąd musi byd ona wypakowywana.
  • 15. int zlo = 42; ArrayList al = new ArrayList(); al.Add(zlo); //pakowanie zlo = (int)al[0] + 1; //wypakowywanie
  • 16. int zlo = 42; Queue kolejka = new Queue(); kolejka.Enqueue(zlo); //wrzucanie do kolejki zlo = (int)kolejka.Dequeue(); //wyciąganie z kolejki
  • 18. class Kobieta { public void Zabawa(FacetJohnyBrawo facet) { Console.WriteLine("Dobrze się bawiłam"); } }
  • 19. class FacetJohnyBrawo { ArrayList mojekobiety = new ArrayList(); public void DodajKobiete(Kobieta kobieta) { mojekobiety.Add(kobieta); } public void IdzNaRandkePoKoleji() { foreach (var kobieta in mojekobiety) { Console.WriteLine(kobieta); } } }
  • 20.
  • 21. FacetJohnyBrawo johnyBravo = new FacetJohnyBrawo(); johnyBravo.DodajKobiete(new Kobieta()); johnyBravo.DodajKobiete(new Kobieta()); johnyBravo.DodajKobiete(new Kobieta()); johnyBravo.DodajKobiete(new Kobieta()); johnyBravo.IdzNaRandkePoKoleji();
  • 22.
  • 23.
  • 24. class FacetJohnyBrawo { List<Kobieta> mojekobiety = new List<Kobieta>(); public void DodajKobiete(Kobieta kobieta) { mojekobiety.Add(kobieta); } public void IdzNaRandkePoKoleji() { foreach (var kobieta in mojekobiety) { kobieta.Zabawa(this); } } }
  • 26. int dobro = 0; Queue<int> kolejka = new Queue<int>(); kolejka.Enqueue(dobro); dobro = kolejka.Dequeue();
  • 27. public class Queue<T> : //...public class Stack<T> : //... public void Enqueue(T item); public T Dequeue();
  • 28. T • Parametr T zastępuje dany typ i jest zastąpiony prawdziwym typem w czasie deklaracji danej klasy Generics. • Do tych klas nie można więc już umieścid innych typów od tych, które zadeklarowaliśmy zamiast <T>. • Mechanizm T jest bardziej skomplikowany niż się wydaje. Jego działanie nie polega dosłownie na zastąpieniu tego elementu jakby kod to był jakiś notatnik, czy word. Kompilator dokonuje dokładną i kompletną substytucje w taki sposób ,aby T mogło referowad się do każdego typu. • Jednak przykładowo Queue<string> i Queue<int> powinny byd traktowane jak dwa oddzielne typy danych. Specyficzne typy klas Generics nazywane są zbudowanymi typami “constructed types” .
  • 29. DEMO
  • 31. Wstęp • W WPF mamy do dyspozycji kontrolki , jak przyciski czy textbox-y. Kiedy klikasz na przycisk, czy piszesz jakiś tekst oczekujesz , że dane zdarzenie wykona się natychmiastowo. W rzeczywistości tak nie jest. • Aplikacja musi się na chwile zatrzymad i odpowiednio przekierowad działania użytkownika. Nie dotycz to tylko aplikacji z interfejsem użytkownika (UI) ,ale do każdej innej aplikacji, w której czynnośd X musi byd wykonana natychmiastowo bez względu na inne procesy w tle.
  • 32. • Delegata jest wskaźnikiem do danej metody. Poprzez daną delegate możesz wywoład daną metodę. Kiedy wywołujesz daną delegatę program tak naprawdę wykonuje daną metodę, do której delegata się referowała.
  • 33. C++ Jeśli znasz język programowania taki jak C++ to zapewne zdałeś sobie już sprawę , że delegata działa podobnie do wskaźnika funkcji. Jednak delegaty są bezpieczniejsze, dana delegata może tylko referowad się do metody, której sygnatura jest zgodna z delegatą. Nie możesz wywoład delegaty, która nie referuje się do właściwiej dla siebie metody
  • 34. Problem ze zrozumieniem • Znając życie, ponieważ sam miałem z tym problem, na pewno się teraz zastanawiasz, po co w ogóle są delegaty? • Jeśli chcę wywoład metodę X to ją wywołuję po co mi delegata, która robi dokładnie to samo tylko pozwala wywoład metodę pod inną nazwą. • Czas na przykład.
  • 35. Sytuacja • Mamy dziecko i oboje rodziców. Dziecko płacze i trzeba je przewinąd. Ponieważ matka jest zajęta deleguje to zadanie ojcu. • A ojciec ma w swojej klasie metodę, którą zadnie to może wykonad. • Bez delegat przykład wygląda tak.
  • 36. class Dziecko { private bool glodny;//tak rodzice nie wiedzą co chce dziecko :) private Mama mama; private Tata tata; public void MozeChceJesc() { if (glodny == false) { Console.WriteLine("Dziecko nie jest głodne"); } else { if (mama.zmęczona == false) { mama.Nakarmienie(this); } else { tata.Nakarmienie(this); } glodny = false; } } //a ty myślałeś ,że dzieci biorą się z pszczółek i kwiatków public Dziecko(Mama duzaCieplaPlama, Tata duzaZnajomaPlama) { //z puntu nowonarodzonego dziecka wszystko jest jedną fajną plamą mama = duzaCieplaPlama; tata = duzaZnajomaPlama; } }
  • 37. Opis cz1 • Zakładamy ,że wszystkie obowiązki wykonuje zawsze mama ,ale jeśli jest ona zmęczona to obowiązek przechodzi na ojca ,a ojciec nie może byd zmęczony. • Ponieważ rodzice nie wiedzą, co dziecko chce , jego pola jak “głodny” są prywatne i nie mają właściwości przypisanych do nich.
  • 38. Opis cz2 • Istnieje jednak dużo większy problem. • Te rozwiązanie nie jest elastyczne. Gdyby nagle się okazało się, że babcia i dziadek też mogą zajmowad się tymi obowiązkami musiałbym dodad ich do klasy Dziecko. • Jednym słowem obecne rozwiązane jest stworzone do jednego konkretnego rozwiązania.
  • 39. Co należy zrobić • Tę logikę wypadało jakoś oddzielid od klasy dziecko. Dlatego stworzenie abstrakcyjnej klasy bazowej “OpiekunDziecka” też tutaj do kooca nie rozwiąże sprawy. • W programowaniu nie jest to sympatycznie odbierane zwłaszcza jeśli programista spodziewa się , że ten kod może ulec zmianie. W pracach domowych na studiach możesz sobie na to pozwolid ale nie w życiu.
  • 41. Co należy zrobić • Mimo, iż metody mają różne nazwy i mogą pochodzid od różnych klas wszystkie muszą mied podobny “kształt”. • W tym przykładzie każda z metod przyjmuje parametr klasy Dziecko i nie zwraca żadnej wartości. Format wszystkich tych metod będzie następujący. void Nazwa(Dziecko dziecko)
  • 42. delegate void MozeChceJescDelgata(Dziecko dziecko); • Na co trzeba zwrócid uwagę: Użycie słowa kluczowego “delegate” przy deklaracji delegaty • Delegata definiuje kształty metody, do które się referuje. Metoda nie może niczego zwracad “void” i musi przyjmowad jeden parametr “dziecko”.
  • 43. Po stworzeniu delegaty możesz stworzyd jej instancje. Przy użyciu operatora += możesz przypisad do niego odpowiednią metodę. Zrobię to w konstruktorze klasy Dziecko ,aby nie wnikad na razie w szczegóły sytuacyjne. Mam przecież wyjaśnid jak działają delegaty. class Dziecko { delegate void mozeChceJescDelgata(Dziecko dziecko); private mozeChceJescDelgata mozeChceJesc; // instancja delegaty public Dziecko(Mama mama) { this.mozeChceJesc += mama.Nakarmienie; } }
  • 44. Dodanie metod do delegat • Dodajesz metodę do delegaty w tym momencie metoda nie jest wywoływana. • Operator „=+” dla delegaty jest nadpisany i ma swoje unikalne zastosowanie. Zauważ też , że do metody nie dodałem żadnego parametru i nie ma nawet nawiasów (). • Istnieje jeszcze inny sposób na przypisanie delegaty do odpowiedniej metody jednak wyrażenie += jest bezpieczniejsze w użyciu oraz inicjacja przebiegnie automatycznie. Ten inny sposób wygląda tak.
  • 45. this.mozeChceJesc = new mozeChceJescDelgata(mama.Nakarmienie); • Jak widzisz ilośd kodu jest trochę większa ale w ten sposób instancja delegaty będzie zawsze odwoływad się do jednej metody. • Używając znaku += tak naprawdę dodajesz następne możliwe metody, które mają się wykonad
  • 46. Uwaga • Wywołanie delgaty, która nie jest zainicjowana oraz nie ma przypisanej żadnej metody grozi wyrzuceniem wyjątku “NullReferenceException”.
  • 47. Przykład CDN • Tak jak powiedziałem wcześniej używając wyrażenia += skutkuje przypisaniem kolejnej metody do danej delegaty. Jest to zwykle zaleta niż wada. Dlaczego? • Otóż wyobraź sobie taką sytuacje. Skoro rodzice nie wiedzą, co chce dziecko, to najczęściej wykonują wszystkie operacje po kolei. Przynajmniej tak to wygląda z programistycznego punktu widzenia ponieważ obiekty mama i tata nie posiadają sztucznej inteligencji aby zgadywad precyzyjnie co chce dziecko xD.
  • 48. class Dziecko { delegate void cosChceDelgata(Dziecko dziecko); private cosChceDelgata cosChce; // instancja delegaty public Dziecko(Mama mama) { this.cosChce += mama.Przewiniecie; this.cosChce += mama.Nakarmienie; this.cosChce += mama.Ululanie; } public void CosChceMetoda() { this.cosChce(this); } }
  • 49. Dziecko Rosesmary = new Dziecko(new Mama()); Rosesmary.CosChce();
  • 50. Mocna strona delegat • To bardzo mocna strona delegaty wszystkie metody wykonały się i to w określonej kolejności. W koocu wolałbym przypisad 100 metod do jednej delegaty, niż pisad 100 linijek za każdym razem, gdy chcę wykonywad te operacje. • Delegaty też dają pewną elastycznośd bo przecież kolejnośd działao była zadeklarowana w konstruktorze, a nie bezpośrednio w kodzie jakbym pisał metoda po metodzie.
  • 51. Możesz też usuwad metody za pomocą operatora –=. this.cosChce -= mama.Nakarmienie;
  • 52. Publiczne Delegaty • Obecnie opiekunowie dziecka byliby dodawani w konstruktorze ponieważ obecnie instancja delegaty jest prywatna. • Warto ją zmienid na publiczną w ten sposób klasa dziecko powinna byd niezależna od swoich opiekunów
  • 53. public cosChceDelgata cosChce; // instancja delegaty
  • 54. delegate void cosChceDelgata(Dziecko dziecko); private cosChceDelgata _cosChce; // instancja delegaty public cosChceDelgata CosChce { get { return cosChce; } set { cosChce = value; } }
  • 55. Heremtyzacja dziecka • Można też zaszaled i dad klasie Dziecko pełne hermetyczne rozwiązanie zakładając nawet , że dziecko nie wie co rodzice będą robid by zaspokoid jego potrzeby. • Biedny dzieciak nawet nie wie, co mu dolega i kiedy to przechodzi. Zasada hermetyzacji jest taka brutalna.
  • 56. public delegate void cosChceDelgata(Dziecko dziecko); private cosChceDelgata cosChce; // instancja delegaty public void Dodaj(cosChceDelgata MetodaX) { this.cosChce += MetodaX; } public void Usun(cosChceDelgata MetodX) { this.cosChce -= MetodX; }
  • 58. class MaszynaPracujaca { public void UruchomMaszyne() { Console.WriteLine("Maszyna Uruchomiona"); } public void ObliczWzorZimnejFuzji() { Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G"); } public void OdnajdzSensZycia() { Console.WriteLine("42"); } public void WylaczMaszyne(int czasZamkniecta) { Console.WriteLine("Zamkniecie za {0}", czasZamkniecta); } }
  • 59. class MaszynaZadan { public delegate void listZadanDelegata(); private listZadanDelegata listaZadan; public MaszynaZadan(MaszynaPracujaca maszyna) { listaZadan += maszyna.UruchomMaszyne; listaZadan += maszyna.ObliczWzorZimnejFuzji; listaZadan += maszyna.OdnajdzSensZycia; } public void RozpocznijZadania() { listaZadan(); } }
  • 60. MaszynaZadan mz = new MaszynaZadan(new MaszynaPracujaca()); mz.RozpocznijZadania(); Jak dobrze pamiętasz mówiłem też coś o zasadzie hermetyzacji czyli klasa MaszynaZadan jest chwilowo źle napisana ponieważ jej działanie jest zależne od klasy MaszynaPracująca. Problem ten można rozwiązad w następujący sposób. Sprawiając , że klasa MaszynaZadan może byd elastycznie dostosowywana.
  • 61. class MaszynaZadan { public delegate void listZadanDelegata(); private listZadanDelegata listaZadan; public void Dodaj(listZadanDelegata MetodaX) { listaZadan += MetodaX; } public void Usun(listZadanDelegata MetodX) { listaZadan -= MetodX; } public void RozpocznijZadania() { if (listaZadan != null) listaZadan(); } }
  • 62. ADAPTERY Może nie zauważałeś ,ale w klasie MaszynaPracująca jest metoda “WylaczMaszyne”.
  • 63. class MaszynaPracujaca { public void UruchomMaszyne() { Console.WriteLine("Maszyna Uruchomiona"); } public void ObliczWzorZimnejFuzji() { Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G"); } public void OdnajdzSensZycia() { Console.WriteLine("42"); } public void WylaczMaszyne(int czasZamkniecta) { Console.WriteLine("Zamkniecie za {0}", czasZamkniecta); } }
  • 64. Metoda ta przyjmuje parametr int czyli jej kształt bądź jak wolisz sygnatura jest inna niż innych metod tej klasy. Ten kształt jest nie zgodny z sygnaturą delegaty, która przyjmuje tylko metody bezparametrowe.
  • 65. class MaszynaPracujaca { public void UruchomMaszyne() { Console.WriteLine("Maszyna Uruchomiona"); } public void ObliczWzorZimnejFuzji() { Console.WriteLine("Obliczyłem wzór na zimną fuzje: X^6 + Lin(3) * G"); } public void OdnajdzSensZycia() { Console.WriteLine("42"); } public void WylaczMaszyne(int czasZamkniecta) { Console.WriteLine("Zamkniecie za {0}", czasZamkniecta); } public void NatchmiastoweWylaczenie() { this.WylaczMaszyne(0); } }
  • 66. mz.Dodaj(mp.NatchmiastoweWylaczenie); //dla klasy która jest w wersji konstruktora listaZadan += maszyna.NatchmiastoweWylaczenie;
  • 67. Wyrażenie Lambda • Oczywiście pojawiło się pytanie gdzie ta metoda adaptująca powinna byd. Oczywiście jest ona w klasie “MaszynaPracująca” stąd to słowo kluczowe “this” jako wskazówka. Jednak co jeśli nie możemy zmienid zawartości tej klasy. • Nawet jeśli możemy zmienid zawartośd tej klasy, to co jeśli ta klasa jest gigantyczna. • Tak czy siak, ta metoda istnieje tylko z powodu jednej delegaty i raczej na pewno nie będzie używana nigdzie indziej. • W C# do takich przypadków lepiej zastosowad wyrażenie lambda czyli naszą gwiazdę tego wykładu.
  • 68. Wyrażenie Lambda • Wyrażenie lambda zwraca metodę. • Brzmi to fantastycznie chociaż na pewno możesz się zastanawiad jako to w ogóle działa. Zwykle wyrażenia w C# zwracają jakąś wartośd “X”. • W językach programowania funkcjonalnego jest to dośd często spotykane zachowanie. Wraz z C# 3.0 pojawiły się wyrażenia lambda (jak i zapytania LINQ) i od tamtej pory twój kod miejscami może przypominad język funkcjonalny.
  • 69. Programowanie funcjonalne • Oto mała informacja z Wikipedii z nagłówka “Functional programming in non-functional languages”w wpise o językach programowania funkcjonalnego. Jak widzisz pewne trendy przechodzą nawet na języki programowania, które nie są funkcjonale i nie mówi się tu tylko o C#. Doszło to nawet do języka PHP, he…no tego bym się nie spodziewał. Kiedyś nie był to obiektowy język. • Z tego co kiedyś czytałem w kolejnej wersji języka Java też mają pojawid się te wyrażenia.Wyrażenia lambda są nawet obecne we wzorcach projektowych.
  • 70. Tworzenie metod • Koniec jednak tej lektury. Wyrażenie lambda nie jest takie skomplikowane. To tylko kolejny zestaw znaków, które trzeba zapamiętad i tyle. Zresztą jest ono bardzo użyteczne , a więc okazja użycia pojawi się jeszcze nie raz. • Typowa metoda musi składad się z 4 elementów: – Nazwy – Listy parametrów – Ciała metody – Zwracanej wartości
  • 71. Wyrażenie Lambda • Wyrażenie lambda zawiera tylko dwa elementy: listę parametrów oraz ciało metody. • Wyrażenia Lambda nie określają swojej nazwy. • Wyrażenie lambda nie definiuje też zwrotnego parametru. Jednak jakiś parametr może byd zwracany jeśli wynika to z zawartości jej ciała. • Wracając do problemu z metodą “WyłaczMaszyne(int czasZamkniecia)” . • Musimy stworzyd adapter metody WylaczMaszyne w taki sposób ,aby nie miała ona żadnych parametrów i mogłaby byd dodana do instancji delegaty “ListaZadan”.
  • 72. mz.Dodaj( (() => { mp.WylaczMaszyne(0);}) ); //dla klasy która jest w wersji konstruktora listaZadan += (() => { maszyna.WylaczMaszyne(0); });
  • 73.
  • 75. DEMO
  • 76. Lambda podsumowanie • Czas na podsumowanie tego kodu i to nie za pomocą zielonego komentarza w kodzie. Wyrażenia lambda mogą zwracad wartości jednak muszą one pasowad do typu danej delegaty, do której są dodawane. • Ciało wyrażenia lambda może byd prostym wyrażeniem albo blokiem kodu C# z wieloma stwierdzeniami, wezwaniami innych metod, definicją zmiennych i innych rzeczy. • Zmienne zdefiniowane wewnątrz wyrażenia lambda istnieją tylko w tym bloku kodu i znikają gdy metoda się skooczy,
  • 77. Lambda podsumowanie • Wyrażenie lambda ma dostęp do wszystkich zmiennych i metod znajdujących się po za tym wyrażeniem. W czasie wykonywania wyrażenia zmienne ulegają zmianie tymczasowo. Warto o tym pamiętad. • Jeśli wyrażenie lambda pobiera jakieś parametry możesz nie podawad ich typów ponieważ kompilator skojarzy je z kontekstu danego wyrażenia. Jednak przy słowach kluczowych jak ref i out musisz też podad ich typ. • Wyrażenie lambda może zmienid wartości na zawsze jeśli są one przesłane do metody za pomocą słów kluczowych ref i out.
  • 79. Metody Anonimowe • W C# 2.0 czyli przed wyrażeniami lambda były metody anonimowe, które spełniały podobny cel do wyrażeo lambda ale nie były tak elastyczne. • Anonimowe metody zostały dodane po to aby dad programistom możliwośd definiowania delegat bez określenia ich nazw. Metody te zawierały w sobie tylko swoją definicję.
  • 80. listaZadan += delegate { maszyna.WylaczMaszyne(0); }; mz.Dodaj(delegate { mp.WylaczMaszyne(0); });
  • 81. Aby stworzyd metodę anonimową musisz użyd słowa kluczowego delegate. Parametry też muszą byd określone w nawiasach przy słowie kluczowym delegate. operacjeMatDwuArg += delegate(int x, int y) { return x - y; };
  • 82. Metody Anonimowe • Zostały jednak one osunięte w cieo. Złożone zadania wyglądają o wiele lepiej w wyrażeniu lambda dlatego też już prawie nikt nie pamięta o tamtej formie zapisu. Chyba ,że ktoś z jakiegoś powodu musi programowad w C# 2.0. • To taka ciekawostka ponieważ wyrażenia lambda są lepsze. Może jednak kiedyś spotkasz się z takimi zapisami.
  • 84. Wstęp • Jednak to jeszcze nie koniec. Co prawda możesz wywoład wiele metod nie bezpośrednio za pomocą delegaty, ale wciąż musisz ją wywoład jawnie. Z programistycznego punktu widzenia dobrze byłoby , aby delegaty uruchomiały się automatycznie gdy coś ważnego się wydarzy. • Przykładowo, w przypadku przegrzewania się reaktora atomowego wywoład odpowiednią delegate, która wykona wszystkie metody po kolei w celu jego wyłączenia . • W wielu wypadkach klasy znajdujące się w .NET pokazują użycie zdarzeo (event). Zdarzenia są używane do zdefiniowania i przechwytywania określonych akcji .Określają one też użycie odpowiedniej delegaty, która sobie z daną sytuacją X poradzi.Większośd kontrolek z WPF ,Windows Forms, Silverlight , a nawet z ASP.NET używa zdarzeo. Nawet np. sama klasa okna głównego w WPF przechowuje następujące zdarzenia.
  • 85.
  • 86. Zdarzenia • Zdarzenie może byd zadeklarowane tylko w klasie i to ona jest zawsze źródłem tego zdarzenia. Źródłem danego zdarzenia jest zazwyczaj klasa, która monitoruje dane środowisko oraz wywołuje zdarzenie w momencie spełnienia danego warunku. • Niektóre klasy mają np. zdarzenia, które zostaną wywołane w przypadku zajścia błędu. Idąc tym tropem przyszedł mi głowy następujący przykład zastosowania zdarzenia. • Mamy do dyspozycji klasę “PobieraczPlików” , której zadaniem jest pobranie poprzez sied różnego rodzaju plików.
  • 87. Zdarzenia • Klasa ta ma dwa pola – liczbeDoPobraniaPlików”, która będzie mówid nam ile plików ma ta klasa pobrad. – “liczbePobranychPlikow” , która będzie opisywad ile plików zostało już pobranych.
  • 88. • Zdarzenie “PrzyBledziePobierania” zajdzie jeśli klasa wykryje , że dane pobieranie nie skooczyło się prawidłowo. Inne zdarzenie “SkonczonePobieranie” zajdzie gdy liczba pobranych plików będzie równa liczbie plików, którą planowaliśmy pobrad. • Zdarzenia te będą przechowywad listę metod, które mają byd wywoływane w czasie ich zajścia. Te metody są nazywane subscribers , co dosłownie można przetłumaczyd jako wyraz subskryptami. Jednak na pewno nie jest to prawidłowe tłumaczenie (nie ma takiego słowa w języku polskim). Metody te obsłużą nasze zdarzenie i wykonają odpowiednie akcje np. przy “PrzyBledziePobierania” użytkownik zostanie poinformowany , że dany plik nie mógł zostad pobrany.
  • 90. class PobieraczPlikow { public delegate void BladPobierniaDelegata(string wiadomosc); public delegate void SkonczonePobieranieDelegata(); private int liczbaPobranychPlikow; private int liczbaDoPobraniaPlikow; }
  • 91. class PobieraczPlikow { public delegate void BladPobierniaDelegata(string wiadomosc); public event BladPobierniaDelegata PrzyBlendziePobierania; public delegate void SkonczonePobieranieDelegata(); public event SkonczonePobieranieDelegata SkonczonePobieranie; private int liczbaPobranychPlikow; private int liczbaDoPobraniaPlikow; }
  • 93. class PobieraczPlikow { public void WystapilBlad() { if (PrzyBlendziePobierania != null) { PrzyBlendziePobierania("Wystapił błąd"); }
  • 94. Jak widzisz jeśli dana delegata w zdarzeniu definiuje jakieś parametry muszą one byd podane w trakcie ich wywołania. Zdarzenia też mają pewną istotną wbudowaną funkcje mogą one byd wywołane wewnątrz klasy, która je definiuje w tym wypadku wewnątrz klasy “PobieraczPlikow”. Próba wywołania zdarzenia poza tą klasą skooczy się błędem w czasie kompilacji programu.
  • 95. class PobieraczPlikow { //konstruktor public PobieraczPlikow(int l) { liczbaDoPobraniaPlikow = l; } //proste wywołanie zdarzenia public void WystapilBlad() { if (PrzyBlendziePobierania != null) PrzyBlendziePobierania("Wystapił błąd"); } public delegate void BladPobierniaDelegata(string wiadomosc); public event BladPobierniaDelegata PrzyBlendziePobierania; public delegate void SkonczonePobieranieDelegata(); public event SkonczonePobieranieDelegata SkonczonePobieranie; private int liczbaPobranychPlikow; public int LiczbaPobranychPlikow { get { return liczbaPobranychPlikow; } set { if (value == liczbaDoPobraniaPlikow) { if (SkonczonePobieranie != null) SkonczonePobieranie(); } liczbaPobranychPlikow = value; } } private int liczbaDoPobraniaPlikow; public int LiczbaDoPobraniaPlikow { get { return liczbaDoPobraniaPlikow; } } }
  • 97. Zdarzenia w WPF • Pisałem już wcześniej , że WPF, Silverlight, ASP.NET w swoich klasach i kontrolkach używa zdarzeo do kontrolki nad graficznym interfejsem użytkownika. • Ucząc się którejś z tych technologii czasami spotkasz się ze zdarzeniami. Nawet początkujący programiści z nich korzystają i nie wiedzą dokładnie jak one działają ponieważ wymaga to poznania wielu zagadnieo jak np. delegaty. • No cóż , dla uproszczenia nie będę w tym wpisie zagłębiad się jak zdarzenia są skonstruowane w ASP.NET. Zobaczmy jak zdarzenia są zrobione w WPF zwłaszcza , że WPF i Silverlight w tym wypadku powinni byd do siebie podobni. • Kontrolka przycisku dziedziczy po klasie bazowej “ButtonBase”. Ma to sens ponieważ w WPF są też inne przyciski od tego standardowego jak np. ToggleButton.
  • 98. public class Button : ButtonBase
  • 99. • Przycisk dziedziczy po niej zdarzenie “Click” , który jest typem delegaty “RoutedEventHandler”. • Delegata ta spodziewa się dwóch parametrów: referencji do obiektu, który spowodował wywołanie tego zdarzenia oraz obiekt klasy “RoutedEventArgs” , który przechowuje różne dodatkowe informacje na temat tego zdarzenia. • Jest to pomysłowe ponieważ nie chciałbyś widzied całej linijki parametrów za każdym razem gdy obsługujesz dane zdarzenie.
  • 100. public abstract class ButtonBase : ContentControl, ICommandSource { public event RoutedEventHandler Click; // Summary: // Raises the System.Windows.Controls.Primitives.ButtonBase.Click routed event. protected virtual void OnClick();
  • 101. Button • Klasa ButtonBase posiada też metodę wirtualną dostępną tylko dla klas pochodnych, która może wywoład bezpośrednio to zdarzenie. • Klasa Button uruchamia to zdarzenie gdy klikniesz na przycisk . Jednak co dokładnie się dzieje w momencie jego kliknięcia? Skąd klasa to wie ? To wychodzi poza ramy tego wpisu. • W WPF mamy XAML , a w nim najczęściej mówimy, która kontrolka obsługuje jakie zdarzenie. Jest to wygodne ale warto sobie uświadomid , że kod łączący naszą metodę np. ”Button_Click” z wydarzeniem wciąż istnieje jest on tylko wygenerowany przez kompilator. W sumie to dużo rzeczy w kompilatorze się dzieje aby powiązad kod XAML z kodem w C#.
  • 102. private void Button_Click(object sender, RoutedEventArgs e) { }
  • 103. Button • Zdarzenia w wielu kontrolkach działają według tego samego wzoru. Sygnatura delegata w zdarzeniach w kontrolkach jest prawie zawsze taka sama. Delegata mówi , że ta metoda nic nie może zwracad “void” oraz pokazuje dwa parametry: sender: Referencja do kontrolki, która wywołała dane zdarzenie. • e: Zbiór pomocniczych argumentów, które otrzymało dane zdarzenie. • Mając do dyspozycji argument “seneder” teraz nic nie stoi na przeszkodzie aby dana metoda X obsługiwała zdarzenie Click dla 100 przycisków skoro możesz sprawdzid, który z nich wywołał to zdarzenie.