REKLAMA. www.sdjournal.pl. Posiadamy bazę 90 tysięcy specjalistów z różnych działów IT!



Podobne dokumenty
msgbox("akcja: Początek, argument: " + argument.tostring()); Thread.Sleep(1000); //opóźnienie msgbox("akcja: Koniec"); return DateTime.Now.

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Czym są właściwości. Poprawne projektowanie klas

znajdowały się różne instrukcje) to tak naprawdę definicja funkcji main.

Instrukcja laboratoryjna nr.4

Wskaźniki a tablice Wskaźniki i tablice są ze sobą w języku C++ ściśle związane. Aby się o tym przekonać wykonajmy cwiczenie.

Baza danych sql. 1. Wprowadzenie

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

C# 6.0 : kompletny przewodnik dla praktyków / Mark Michaelis, Eric Lippert. Gliwice, cop Spis treści

Informacje ogólne. Karol Trybulec p-programowanie.pl 1. 2 // cialo klasy. class osoba { string imie; string nazwisko; int wiek; int wzrost;

Wprowadzenie do projektu QualitySpy

Rozdział 3. Zapisywanie stanu aplikacji w ustawieniach lokalnych

Instrukcja laboratoryjna cz.3

Programowanie obiektowe

Instrukcja laboratoryjna

Temat: Ułatwienia wynikające z zastosowania Frameworku CakePHP podczas budowania stron internetowych

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Wykład 8: klasy cz. 4

Dokumentacja do API Javy.

Rozdział 4 KLASY, OBIEKTY, METODY

Podczas dziedziczenia obiekt klasy pochodnej może być wskazywany przez wskaźnik typu klasy bazowej.

Programowanie zaawansowane

2.5 Dzielenie się wiedzą

Baza danych sql. 1. Wprowadzenie. 2. Repozytaria generyczne

Instalacja systemu zarządzania treścią (CMS): Joomla

MVVM Light Toolkit. Julita Borkowska

Programowanie zespołowe

Informatyka II. Laboratorium Aplikacja okienkowa

Wyjątki. Streszczenie Celem wykładu jest omówienie tematyki wyjątków w Javie. Czas wykładu 45 minut.

Laboratorium 1 - Programowanie proceduralne i obiektowe

Podstawy Programowania 2

MonoGame. Wieloplatformowe gry w C# Mateusz Cicheński

Programowanie współbieżne Wykład 8 Podstawy programowania obiektowego. Iwona Kochaoska

Instrukcja instalacji Control Expert 3.0

Implementacja aplikacji sieciowych z wykorzystaniem środowiska Qt

Klasy cd. Struktury Interfejsy Wyjątki

Tworzenie i wykorzystanie usług sieciowych

Aplikacje w środowisku Java

Narzędzia i aplikacje Java EE. Usługi sieciowe Paweł Czarnul pczarnul@eti.pg.gda.pl

Smarty PHP. Leksykon kieszonkowy

Wykład 4: Klasy i Metody

Zawartość. Wstęp. Moduł Rozbiórki. Wstęp Instalacja Konfiguracja Uruchomienie i praca z raportem... 6

Z pojedynczym obiekcie zasady grupy znajdziemy dwa główne typy ustawień:

Klasy Obiekty Dziedziczenie i zaawansowane cechy Objective-C

Obiektowy PHP. Czym jest obiekt? Definicja klasy. Składowe klasy pola i metody

Symulator tabletu z systemem Windows 8.

Forex PitCalculator INSTRUKCJA UŻYTKOWNIKA

Projektowanie baz danych za pomocą narzędzi CASE

PHP 5 język obiektowy

Wykład 3 Składnia języka C# (cz. 2)

Wdrożenie modułu płatności eservice. dla systemu Zen Cart

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Java pierwszy program w Eclipse «Grzegorz Góralski strona własna

Cel: Przypisujemy przyciskom określone funkcje panel górny (Panel1)

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

Programowanie obiektowe

MATERIAŁY DO ZAJĘĆ I. Podstawowe pojęcia. Algorytm. Spis treści Przepis

Backend Administratora

[1/15] Chmury w Internecie. Wady i zalety przechowywania plików w chmurze

Leszek Stasiak Zastosowanie technologii LINQ w

using System;... using System.Threading;

5.4. Tworzymy formularze

System Obsługi Zleceń

Programowanie obiektowe zastosowanie języka Java SE

Wdrożenie modułu płatności eservice. dla systemu oscommerce 2.3.x

Jeśli chcesz łatwo i szybko opanować podstawy C++, sięgnij po tę książkę.

REFERAT O PRACY DYPLOMOWEJ

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

UNIFON podręcznik użytkownika

Instrukcja użytkownika

Po uruchomieniu programu nasza litera zostanie wyświetlona na ekranie

Języki i techniki programowania Ćwiczenia 2

WINDOWS Instalacja serwera WWW na systemie Windows XP, 7, 8.

Instrukcja instalacji

Wyjątki (exceptions)

Materiały do zajęć VII

Programowanie obiektowe

Zadanie polega na stworzeniu bazy danych w pamięci zapewniającej efektywny dostęp do danych baza osób.

Programowanie obiektowe

Zaawansowane aplikacje internetowe - laboratorium

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1

Wskaźnik może wskazywać na jakąś zmienną, strukturę, tablicę a nawet funkcję. Oto podstawowe operatory niezbędne do operowania wskaźnikami:

Modele danych walidacja widoki zorientowane na model

Praca w środowisku Visual Studio 2008, Visual C

PLAN WYNIKOWY PROGRAMOWANIE APLIKACJI INTERNETOWYCH. KL IV TI 6 godziny tygodniowo (6x15 tygodni =90 godzin ),

Pracownia internetowa w każdej szkole (edycja Jesień 2007)

Widoczność zmiennych Czy wartości każdej zmiennej można zmieniać w dowolnym miejscu kodu? Czy można zadeklarować dwie zmienne o takich samych nazwach?

REFERAT PRACY DYPLOMOWEJ

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Programowanie obiektowe

APLIKACJA SHAREPOINT

Płace Optivum. 1. Zainstalować serwer SQL (Microsoft SQL Server 2008 R2) oraz program Płace Optivum.

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?

PROE wykład 2 operacje na wskaźnikach. dr inż. Jacek Naruniec

PHP: bloki kodu, tablice, obiekty i formularze

Języki i paradygmaty programowania doc. dr inż. Tadeusz Jeleniewski

Programowanie obiektowe

Kadry Optivum, Płace Optivum. Jak przenieść dane na nowy komputer?

Transkrypt:

REKLAMA Jeżeli jesteś zainteresowany/a reklamą swoich produktów w naszym magazynie Jeżeli jesteś zainteresowany/a wypromowaniem swojej marki wśród specjalistów IT Jeżeli szukasz klientów lub pracowników Zareklamuj się u nas! Posiadamy bazę 90 tysięcy specjalistów z różnych działów IT! W celu uzyskania oferty reklamowej skontaktuj się z nami: sdjpl@sdjournal.pl tel. 799 46 34 76 www.sdjournal.pl 4 Programowanie asynchroniczne nowość języka C# 5.0 Jacek Matulewski Programowanie asynchroniczne to niezwykle istotny element aplikacji Windows Store uruchamianych na nowym ekranie Start Windows 8, gdzie korzystamy z gotowych funkcji asynchronicznych. 10 Co nadchodzi w C# 6.0 Tomasz Pęczek C# jest najpopularniejszym językiem na platformie.net, a także jednym z bardziej popularnych w ogóle (#5 w indeksie PYPL, #6 w indeksie TIOBE). Warto przyjrzeć się jakie zmiany czekają nas w jego następnej wersji. 14 IL Weaving w służbie programiście Marcin Biegała Praca programisty to nie tylko ciekawe problemy, genialne algorytmy i zadowolenie użytkowników. To także tysiące linii kodu, które tworzymy każdego dnia, a które nierzadko nie stanowią funkcjonalności, a są częścią nudnego i powtarzalnego kodu infrastruktury naszych systemów i aplikacji. 22 APLIKACJE W SHAREPOINT 2013 KONFIGURACJA USŁUGI APPS FOR SHAREPOINT Jacek Zięba SharePoint w wersji 2013 oferuje konfiguracje usług do zarządzania aplikacjami wraz z dostępem do Sklepu SharePoint. Całość można konfigurować w Centralnej Administracji w wydzielonym module: Apps. Zanim jednak przejdziemy do tego etapu warto dokładnie przyjrzeć się tematowi. 26 PM w RWD Czyli na co zwrócić uwagę prowadząc projekt RWD? Przemysław Wójcik RWD otacza nas z każdej strony, kolejne serwisy, duże portale dostrzegają potencjał w tego typu rozwiązaniach. Czy warto? Na to pytanie każdy musi odpowiedzieć sobie sam, a w tym artykule powiemy jak wygląda realizacja takiego przedsięwzięcia z punktu widzenia kierownika projektu. 30 Zmiana warty, czyli jak nowoczesne technologie informacyjne odmieniają nasze życie? Mateusz Jabłoński Zmian w codziennym życiu, jakie przyniósł ze sobą rozwój technologii IT, nie sposób nie dostrzec, gdyż są one obecne niemal wszędzie. Software Developer s Journal jest wydawany przez NPRACA Sp. z o.o. Redakcja: sdjpl@sdjournal.pl Kierownik produkcji: Andrzej Kuca Adres korespondencyjny: NPRACA Spółka z o.o. ul. 3 Maja 46, 72-200 Nowogard, Polska Oddział w Warszawie: ul. Postępu 17 D, 02-676 Warszawa, Polska www.sdjournal.pl Facebook: https://www.facebook.com/softwaredevelopersjournal Redakcja dokłada wszelkich starań, by publikowane w piśmie informacje i programy były poprawne, jednakże nie bierze odpowiedzialności za efekty wykorzystania ich; nie gwarantuje także poprawnego działania programów shareware, freeware i public domain. Wszystkie znaki firmowe zawarte w piśmie są własności odpowiednich firm. Zostały użyte wyłącznie w celach informacyjnych. Osoby zainteresowane wspópracą prosimy o kontakt: sdjpl@sdjournal.pl Skład i łamanie / projekt okładki: Digital Concept www.digitalconcept.pl admin@digitalconcept.pl

Programowanie asynchroniczne nowość języka C# 5.0 Programowanie asynchroniczne to niezwykle istotny element aplikacji Windows Store uruchamianych na nowym ekranie Start Windows 8, gdzie korzystamy z gotowych funkcji asynchronicznych. Możemy go jednak użyć we własnych projektach dowolnego typu, w których takie funkcje przygotowujemy to oznacza przygotowywanie funkcji tworzących i zwracających referencję do zadań. W poniższym artykule przedstawię ten mechanizm w sposób, w jaki jego poznanie jest potrzebne, do samodzielnego pisania tego typu metod. A zilustruję to prostymi aplikacjami konsolowymi. DOWIESZ SIĘ Z artykułu dowiesz się w jaki sposób przygotowywać i używać operacje asynchroniczne w C# 5.0. POWINIENEŚ WIEDZIEĆ Wskazana jest znajomość języka C# i platformy.net w stopniu przynajmniej podstawowym. Język C# 5.0 wyposażony został w nowy operator await, ułatwiający synchronizację dodatkowych uruchomionych przez użytkownika zadań. Poniżej zaprezentuję prosty przykład jego użycia, który chyba najlepiej wyjaśni jego działanie. Nie będę szczegółowo omawiał zadań, mam na myśli bibliotekę TPL i jej sztandarową klasę Task, jednak dogłębna znajomość tej biblioteki nie jest konieczna. Spójrzmy na przykład widoczny na listingu 1. Przedstawia on metodę Main aplikacji konsolowej, która definiuje przykładową czynność, zapisuje referencję do niej w zmiennej akcja i wykonuje ją synchronicznie. Czynność ta wprowadza półsekundowe opóźnienie metodą Thread.Sleep, które oczywiście opóźnia jej zakończenie i wydrukowanie informującego o tym komunikatu. W listingu 2 ta sama akcja wykonywana jest asynchronicznie w osobnym wątku utworzonym na potrzeby zdefiniowanego przez nas zadania. Synchronizacja następuje w momencie odczytania wartości zwracanej przez czynność, tj. w momencie odczytania właściwości Result. Jej sekcja get czeka ze zwróceniem wartości aż do zakończenia zadania i tym samym Listing 1. Synchroniczne wykonywanie kodu zawartego w akcji static void Main(string[] args) { // czynność Func<object, long> akcja = (object argument) => { Console.WriteLine("Początek działania akcji - " + argument.tostring()); System.Threading.Thread.Sleep(500); // opóźnienie 0.5s Console.WriteLine("Koniec działania akcji - " + argument.tostring()); return DateTime.Now.Ticks; ; long wynik = akcja("synchronicznie"); Console.WriteLine("Synchronicznie: " + wynik.tostring()); 4 3/2014

Wprowadzenie do programowania asynchronicznego w.net Więcej w... Artkuł jest fragmentem rozdziału z przygotowywanej książki pt. Visual Studio 2013. Podręcznik programowania w C# (z zadaniami), który ukaże się czerwcu 2014 nakładem Wydawnictwa Helion. [LINK: http://helion.pl/ksiazki/visual-studio-2013-podrecznik-programowania-w-c-z-zadaniami-jacek-matulewski-michalgajewski,vs12pa.htm] Informacje na temat programowania równoległego (wiele technologii) i asynchronicznego można również znalaeźć w książce Programowanie równoległe i asynchroniczne w C# 5.0 (Helion, 2013). [LINK: http://helion.pl/ksiazki/programowanie-rownolegle-i-asynchroniczne-w-c-5-0-jacek-matulewski-mateusz-warczak-piotrpeplowski,proch5.htm] Wraz z wersjami 4.0 i 4.5 w platformie.net (oraz w platformie Windows Runtime) pojawiło się wiele metod, które wykonują długotrwałe czynności asynchronicznie. Znajdziemy je w klasie HttpClient, w klasach odpowiedzialnych za obsługę plików (StorageFile, StreamWriter, StreamReader, XmlReader), w klasach odpowiedzialnych za kodowanie i dekodowanie obrazów czy też w klasach WCF. Asynchroniczność jest wręcz standardem w aplikacjach Windows 8 z interfejsem Modern UI (aplikacje Windows Store). I właśnie aby ich użycie było (prawie) tak proste jak metod synchronicznych, wprowadzony został w C# 5.0 (co odpowiada platformie.net 4.5) operator await. Ułatwia on synchronizację dodatkowego zadania tworzonego przez te mewstrzymuje wątek, w którym wykonywana jest metoda Main. Jest to zatem punkt synchronizacji. Zwróćmy uwagę, że po instrukcji zadanie.start, a przed odczytaniem właściwości Result mogą być wykonywane dowolne czynności, o ile są niezależne od wartości zwróconej przez zadanie. Ponadto nie jest konieczne, aby instrukcja odczytania właściwości Result znajdowała się w tej samej metodzie co uruchomienie zadania należy tylko do miejsca jej odczytania przekazać referencję do zadania (w naszym przypadku zmienną typu Task<long>). Zwykle referencję tę przekazuje się jako wartość zwracaną przez metodę uruchamiającą zadanie. Zgodne z konwencją metody tworzące i uruchamiające zadania powinny zawierać w nazwie przyrostek..async (listing 3). Listing 2. Użycie zadania do asynchronicznego wykonania kodu static void Main(string[] args) { // czynność Func<object, long> akcja = (object argument) => { Console.WriteLine("Początek działania akcji - " + argument.tostring()); System.Threading.Thread.Sleep(500); // opóźnienie 0.5s Console.WriteLine("Koniec działania akcji - " + argument.tostring()); return DateTime.Now.Ticks; ; long wynik = akcja("synchronicznie"); Console.WriteLine("Synchronicznie: " + wynik.tostring()); // w osobnym zadaniu Task<long> zadanie = new Task<long>(akcja, "zadanie"); zadanie.start(); Console.WriteLine("Akcja została uruchomiona"); // właściwość Result czeka ze zwróceniem wartości, aż zadanie zostanie zakończone // (synchronizacja) long wynik = zadanie.result; Console.WriteLine("Zadanie: " + wynik.tostring()); www.sdjournal.pl 5

tody. Należy jednak pamiętać, że metodę, w której chcemy użyć operatora await, musimy oznaczyć modyfikatorem async. A ponieważ modyfikatora takiego nie można dodać do metody wejściowej Main, stworzyłem dodatkową, wywoływaną z niej metodę ProgramowanieAsynchroniczne. Prezentuje to listing 4. Operator await zwraca parametr typu Task<> (czyli long w przypadku Task<long>) lub void, jeżeli użyta została wersja nieparametryczna klasy Task. Metody oznaczone modyfikatorem async nazywane są w angielskiej dokumentacji MSDN async methods. Może to jednak wprowadzać pewne zamieszanie. Metody z modyfikatorem async (w naszym przypadku metoda ProgramowanieAsynchroniczne) mylone są bowiem z metodami wykonującymi asynchronicznie jakieś czynności (w naszym przypadku ZróbCośAsync). Osobom poznającym dopiero temat, często wydaje się, że aby metoda wykonywana była asynchronicznie, wystarczy dodać do jej sygnatury modyfikator async. To nie jest prawda. Możemy oczywiście wywołać metodę ZróbCośAsync w taki sposób, że umieścimy ją bezpośrednio za operatorem await, np. long wynik = await Listing 3. Wzór metody wykonującej jakąś czynność asynchronicznie Task<long> ZróbCośAsync(object argument) { // czynność, która będzie wykonywana asynchronicznie Func<object, long> akcja = (object _argument) => { Console.WriteLine( Początek działania akcji - + _argument.tostring()); System.Threading.Thread.Sleep(500); // opóźnienie 0.5s Console.WriteLine( Koniec działania akcji - + _argument.tostring()); return DateTime.Now.Ticks; ; Task<long> zadanie = new Task<long>(akcja, argument); zadanie.start(); return zadanie; static void Main(string[] args) { Task<long> zadanie2 = ZróbCośAsync( zadanie-metoda ); Console.WriteLine( Akcja została uruchomiona (metoda) ); long wynik = zadanie2.result; Console.WriteLine( Zadanie-metoda: + wynik.tostring()); Listing 4. Przykład użycia modyfikatora async i modyfikatora await static async void ProgramowanieAsynchroniczne() { Task<long> zadanie2 = ZróbCośAsync( zadanie-metoda ); Console.WriteLine( Akcja została uruchomiona (metoda) ); long wynik = await zadanie2; Console.WriteLine( Zadanie-metoda: + wynik.tostring()); static void Main(string[] args) { ProgramowanieAsynchroniczne(); Console.WriteLine(); Console.Write( Naciśnij Enter... ); Console.ReadLine(); 6 3/2014

Wprowadzenie do programowania asynchronicznego w.net ZróbCośAsync( async/await );. Czy to ma sens? Wykonywanie metody ProgramowanieAsynchroniczne, w której znajduje się to wywołanie, zostanie wstrzymane aż do momentu zakończenia metody ZróbCośAsync, więc efekt, jaki zobaczymy na ekranie, będzie identyczny jak w przypadku synchronicznym (listing 2). Różnica jest jednak zasadnicza, ponieważ instrukcja zawierająca operator await nie blokuje wątku, w którym wywołana została metoda ProgramowanieAsynchroniczne. Kompilator zawiesza jej wywołanie, przechodząc do kolejnych czynności aż do momentu zakończenia uruchomionego zadania. W momencie gdy to nastąpi, wątek wraca do metody ProgramowanieAsynchroniczne i kontynuuje jej działanie. Zawieszenie działania metody ProgramowaniaAsynchroniczne to obrazowe, ale mało precyzyjne sformułowanie. Tak naprawdę kompilator tnie tę metodę w miejscu wystąpienia operatora await i tę część, która ma być wykonana po zakończeniu zadania i odebraniu wyniku, umieszcza w metodzie zwrotnej (ang. callback). Co więcej, ta metoda zwrotna wcale nie będzie wykonywana w tym samym wątku co pierwsza część metody ProgramowanieAsynchroniczne i metoda Main; wykorzystany zostanie wątek, w którym pracowało zadanie tworzone przez metodę ZróbCośAsync. Rysunek 1. Zadania utworzone w ten sposób nie blokują wątku głównego działają jak wątki tła Listing 5. Przebieg programu Task<long> ZróbCośAsync(object argument) { //czynność, która będzie wykonywana asynchronicznie Func<object, long> akcja = (object _argument) => { Console.WriteLine( Początek działania akcji - + _argument.tostring()); System.Threading.Thread.Sleep(500); //opóźnienie 0.5s Console.WriteLine( Koniec działania akcji - + _argument.tostring()); return DateTime.Now.Ticks; Task<long> zadanie = new Task<long>(akcja, argument); zadanie.start(); return zadanie; static async void ProgramowanieAsynchroniczne() { Task<long> zadanie2 = ZróbCośAsync( zadanie-metoda ); Console.WriteLine( Akcja została uruchomiona (metoda) ); long wynik = await zadanie2; Console.WriteLine( Zadanie-metoda: + wynik.tostring()); static void Main(string[] args) { ProgramowanieAsynchroniczne(); Console.WriteLine(); Console.Write( Naciśnij Enter... ); Console.ReadLine(); www.sdjournal.pl 7

Z tego wynika, że efekt działania operatora await zobaczymy dopiero, gdy metodę ProgramowanieAsynchroniczne wywołamy z innej metody, w której będą dodatkowe instrukcje wykonywane w czasie wstrzymania metody ProgramowanieAsynchroniczne. W naszym przykładzie wywołujemy ją z metody Main, która po wywołaniu metody ProgramowanieAsynchroniczne wstrzymuje działanie aż do naciśnięcia klawisza Enter. W serii instrukcji wywołanie metody oznaczonej modyfikatorem async nie musi się zakończyć przed wykonaniem następnej instrukcji w tym sensie jest ona asynchroniczna. Aby tak się stało, musi w niej jednak zadziałać operator await, w naszym przykładzie czekający na wykonanie metody ZróbCośAsync. W efekcie, jeżeli w metodzie Main usuniemy ostatnie polecenia wymuszające oczekiwanie na naciśnięcie klawisza Enter, metoda ta zakończy się przed zakończeniem metody ProgramowanieAsynchroniczne, kończąc tym samym działanie całego programu i nie pozwalając metodzie ZróbCośAsync wykonać całego zadania. Jeżeli polecenia te są obecne, instrukcje z metody ZróbCośAsync zostaną wykonane już po wyświetleniu komunikatu o konieczności naciśnięcia klawisza Enter wyświetlonego przez metodę Main. Dowodzi tego rysunek 1 (zobacz diagram przy listingu 5). Diagram na listingu 5 obrazuje przebieg programu. Liczby w okręgach oznaczają kolejne ważne punkty programu, m.in. te, w których następuje przepływ wątku z metody do metody (dwa okręgi z tą samą liczbą) lub uruchamiane jest zadanie. Lewa kolumna odpowiada wątkowi głównemu (w nim wykonywana jest metoda Main), a prawa wątkowi tworzonemu na potrzeby zadania, a potem wykorzystywanemu do dokończenia metody zawierającej operator await. Warto nad tym diagramem spędzić chwilę czasu z ołówkiem w ręku i postarać się zrozumieć, jak działa operator await i które fragmenty kodu czekają na zakończenie zadania, a które nie. jacek matulewski Fizyk zajmujący się na co dzień optyką kwantową i układami nieuporządkowanymi na Wydziale Fizyki, Astronomii i Informatyki Stosowanej Uniwersytetu Mikołaja Kopernika w Toruniu. Jego specjalnością są symulacje ewolucji układów kwantowych oddziaływujących z silnym światłem lasera. Od 1998 interesuje się programowaniem dla systemu Windows i platformy.net, a ostatnio grafiką 3D i fizyką w grach. Opublikował kilkanaście książek oraz kilkadziesiąt artykułów w czasopismach Hakin9, Software Developer Journal, Programista i innych. Wierny użytkownik kupionego w połowie lat osiemdziesiątych komputera osobistego ZX Spectrum 48k. REKLAMA kod dla Czytelników: VSRABAT zniżka na 15% na zakup trzech najnowszych książek lub ebook ów autorstwa Jacka Matulewskiego Ważny : do 15.06.2013 http://helion.pl/ksiazki/aspnwe.htm http://helion.pl/ksiazki/jsiqkp.htm http://helion.pl/ksiazki/aspnvs.htm 8

Co nadchodzi w C# 6.0 C# jest najpopularniejszym językiem na platformie.net, a także jednym z bardziej popularnych w ogóle (#5 w indeksie PYPL, #6 w indeksie TIOBE). Warto przyjrzeć się jakie zmiany czekają nas w jego następnej wersji. DOWIESZ SIĘ W jakim kierunku zmierza ewelucja języka C# i jakich nowych elementów należy spodziewać się w jego następnej wersji. POWINIENEŚ WIEDZIEĆ Czym jest język C# i posiadać ogólną wiedzę na temat jego dotychczasowych możliwości. W kwietniu w San Francisco miała miejsce konferencja Build 2014 gdzie Mads Torgersen i Dustin Campbell zaprezentowali część nadchodzących zmian w C# 6.0, które są obecnie dostępne w ramach End User Preview. Zmiany te można zaszeregować do czterech głównych grup. Definiowanie obiektów C# 6.0 przyniesie trzy nowe, bardzo mocno związane ze sobą, cechy. Pierwsza z nich (widoczna na Listingu nr 1) to inicjalizatory dla automatycznych właściwości. Inicjalizacja odbywa się poprzez przypisanie wartości bezpośrednio do pola, które kompilator tworzy dla właściwości. Takie podejście umożliwiło wprowadzenie drugiej nowej cechy, czyli automatycznych właściwości tylko do odczytu. Pierwszym, wręcz narzucającym się, ich zastosowaniem jest inicjalizacja właściwości, które mają zawierać kolekcję. Na Listingu nr 2 znajduje się porównanie dotychczasowego podejścia z nowym. Inicjalizatory właściwości (tak samo jak inicjalizatory pól) są wykonywane zanim obiekt zostanie poprawnie utworzony, co za tym idzie nie mogą się Listing 1. Inicjalizatory dla automatycznych właściwości public class User{ public Guid UserId { get; = Guid.NewGuid(); public string FirstName { get; set; = John ; public string LastName { get; set; = Doe ; Listing 2. Automatyczne inicjalizowanie właściwości przechowującyh kolekcje public class User{... private Dictionary<string, bool> _privileges = new Dictionary<string, bool>(); public Dictionary<string, bool> Privileges { get { return _privileges; // W C# 6.0 ten sam efekt co powyżej będzie można osiągnąć w jednej linijce public Dictionary<string, bool> AutoPrivileges { get; = new Dictionary<string, bool>(); 10 3/2014

Co nadchodzi w C# 6.0 do niego odwoływać. Dodatkowo właściwości tylko do odczytu (w odróżnieniu od pól tylko do odczytu) nie można inicjalizować w konstruktorze przynajmniej w takim jaki obecnie znamy. Z tego powodu właściwości tylko do odczytu miałyby bardzo ograniczone zastosowanie, gdyby nie nowy typ konstruktora. Ten nowy typ konstruktora to Primary Constructor i tak naprawdę pozwala on wyłącznie na zadeklarowanie parametrów bezpośrednio w ramach deklaracji obiektu. Parametry tak zadeklarowane będą widoczne właśnie dla inicjalizatorów. Przykład takiego konstruktora znajduje się na Listingu nr 3. Istnieje również możliwość automatycznego stworzenia pól dla zadeklarowanych parametrów, w tym celu wystarczy je poprzedzić modyfikatorem dostępu z jakim chcielibyśmy aby kompilator utworzył pole. W efekcie parametr ten będzie dostępny pod tą samą nazwą także po stworzeniu obiektu. Niestety konstruktor ten znajdzie swoje zastosowanie tylko w bardzo prostych scenariuszach, ze względu na widoczne już na pierwszy rzut oka ograniczenia. Po pierwsze musi mieć on taką samą widoczność jak cały obiekt, to wyklucza wszelkie przypadki gdzie widoczny publicznie obiekt ma być tworzony wyłącznie wewnętrznie. Brak ciała dla tego konstruktora wprowadza drugie istotne ograniczenie, jakim jest utrudniona walidacja bądź ustawianie wartości domyślnych. Jeżeli jednak te ograniczenia nas nie dotyczą, to konstruktor ten pozwoli znaczącą zmniejszyć ilość kodu, który musielibyśmy napisać. Inicjalizacja kolekcji C# 3.0 wprowadził inicjalizatory dla kolekcji. Jest to bardzo pożyteczna i często używana funkcjonalność. Niestety inicjalizowanie słowników (bądź innych kolekcji typu klucz-wartość) wymagało nieco nienaturalnej składni, jaką widzimy na Listingu nr 4. W nowej wersji języka nadchodzi zmiana, która pozwoli na odwoływanie się bezpośrednio do indeksów podczas inicjalizacji. W efekcie tej zmiany kod z Listingu nr 4 będzie mógł wyglądać jak na Listingu nr 5. Listing 3. Primary Constructor public class User(string firstname, string lastname) { public Guid UserId { get; = Guid.NewGuid(); public string FirstName { get; = firstname; public string LastName { get; = lastname; public Dictionary<string, bool> Privileges { get; = new Dictionary<string, bool>(); Listing 4. Klasyczna inicjalizacja słownika public class User(string firstname, string lastname){... public Dictionary<string, bool> Privileges { get; = new Dictionary<string, bool>{ { ViewContent, true, { AddContent, false, { EditContent, false, { RemoveContent, false ; Listing 5. Inicjalizacja słownika z wykorzystaniem indeksów public class User(string firstname, string lastname) {... public Dictionary<string, bool> Privileges { get; = new Dictionary<string, bool> { [ ViewContent ] = true, [ AddContent ] = false, [ EditContent ] = false, [ RemoveContent ] = false ; www.sdjournal.pl 11

Wersja zaprezentowana na konferencji Build zawierała dodatkowy ukłon w kierunku kluczy będących ciągami znaków nowy operator $. Pozwala on na odwoływanie się do takich kluczy (nie tylko w kontekście inicjalizatora) bezpośrednio, jakby były właściwościami obiektu. Znacznie upraszcza to zapis, co można zobaczyć na Listingu nr 6. Niestety w chwili obecnej status tej funkcjonalności został zmieniony na withdrawn co oznacza, że może się ona nie znaleźć w nadchodzącej wersji. Nowa wersja języka wprowadza także jedną ogólną zmianę w zakresie inicjalizatorów kolekcji (a raczej wyrównuje stan w stosunku do VB.NET). Do tej pory metoda Add, która była wywoływana przez skompilowany kod, musiała być własną metodą obiektu. Od tej pory będzie mogła to być również metoda rozszerzająca (Extension Method). Wyjątki Również pierwsza zmiana w obsłudze wyjątków ma na celu wyrównanie dostępnej funkcjonalności w stosunku do VB.NET (a także F#). Mam tu na myśli filtrowanie wyjątków. Funkcjonalność ta pozwala na dokładanie warunków logicznych do bloków catch i jest szczególnie przydatna w przypadku bardzo generycznych typów wyjątków. Takim wyjątkiem jest COMException, którego faktyczne znaczenie zależy od wartości właściwości ErroCode. Załóżmy, że chcielibyśmy w sposób szczególny obsłużyć błąd RPC_E_ACCESS_ DENIED, natomiast wszystkie pozostałe nas nie interesują. Obecnie wymaga to kodu, który ponownie rzuca przechwycone wyjątki (Listing nr 7). Z nową funkcjonalnością ten sam efekt można uzyskać w sposób pokazany na Listingu nr 8. Kod jest czytelniejszy i nie ma ryzyka zaburzenia stosu. Listing 6. Inicjalizacja słownika z wykorzystaniem operatora $ public class User(string firstname, string lastname) {... public Dictionary<string, bool> Privileges { get; = new Dictionary<string, bool> { $ViewContent = true, $AddContent = false, $EditContent = false, $RemoveContent = false ; Listing 7. Warunkowa obsługa wyjątków - powtórne rzutowanie try{ COMObject.DoSomething(); catch (COMException ex){ if (ex.errorcode == unchecked((int)0x8001011b)){ // Dedykowana obsługa dla RPC_E_ACCESS_DENIED... else { throw; Listing 8. Warunkowa obsługa wyjątków - filtrowanie.cs try { COMObject.DoSomething(); catch (COMException ex) if (ex.errorcode == unchecked((int)0x8001011b)) { // Dedykowana obsługa dla RPC_E_ACCESS_DENIED... 12 3/2014

Co nadchodzi w C# 6.0 Listing 9. Parametry wyjściowe - wcześniejsza deklaracja zmiennej int parsedvalue = 0; if (Int32.TryParse(value, out parsedvalue)) { // Operacja wykorzystująca parsedvalue... Listing 10. Parametry wyjściowe - Dynamic Expressions if (Int32.TryParse(value, out int parsedvalue)){ // Operacja wykorzystująca parsedvalue... Druga zmiana w obsłudze wyjątków to obsługa słowa kluczowego await w blokach catch i finally. Brak tego wsparcie był poważnym ograniczeniem C# 5.0, zwłaszcza w kontekście programowanie dla platformy Windows Phone, gdzie niemal na każdym kroku istniejące API wymusza dostosowanie się do wzorca Task-based Asynchronous Pattern (TAP). W efekcie programiści musieli naprawdę napracować się, aby to ograniczenie obejść. Inne zmiany Choć dwie kolejne zmiany trudno jednoznacznie zaszeregować, to jednak nie ma wątpliwości co do ich użyteczności. Pierwsza z nich to możliwość podania nazwy statycznej klasy jako parametr dyrektywy using. Efektem tego jest widoczność wszystkich metod z tej klasy bez żadnego prefiksu. O ile dla zwykłych metod nie jest to oszałamiająca zmiana, tak jest ona bardzo istotna z perspektywy metod rozszerzających (istniejąca implementacja jeszcze ich poprawnie nie obsługuje, ale ma się to zmienić). Obecnie obiekt jest zmuszony widzieć wszystkie metody rozszerzające z danej przestrzeni nazw, możliwość podanie konkretnego typu pozwoli na o wiele lepszą granulację, czego często brakowało. Druga ze wspomnianych zmian to Declaration Expressions. Pozwalają one na deklaracje zmiennych wewnątrz wyrażenia (z inicjalizacją jak i bez niej). Najszerszym obszarem zastosowania tej konstrukcji okażą się zapewne parametry wyjściowe. Większość osób programujących jakiś czas na platformie.net (zwłaszcza aplikacje z interfejsem użytkownika) widziała przynajmniej raz kod podobny do tego z Listingu nr 9, teraz będzie on mógł wyglądać jak na Listingu nr 10. Innym częstym przypadkiem użycia może okazać się jednoczesne przypisanie i sprawdzenie wyniku operatora as. Podsumowanie Istnieje jeszcze kilka innych nowych cech które ma posiadać język C# w wersji 6.0. Przykładem mogą być reprezentacje tekstowe dla wartości binarnych, które można już testować w języku VB.NET. Na pewno znajdą one swoje zastosowanie przy bardziej czytelnym definiowaniu typów wyliczeniowych służących jako flagi. Ciekawie zapowiadają się również inicjalizatory dla zdarzeń, użycie IEnumerable jako parametr typu params, operator propagacji wartości null (?.) czy operator NameOf. Lista zmian w języku nie jest jeszcze zamknięta i co ważniejsze każdy może mieć na nią wpływ, a nawet spróbować umieścić swój kawałek kodu w kompilatorze.net. Jest to możliwe, ponieważ Microsoft postanowił, że projekt Roslyn będzie od tej chwili projektem open source. Jest to wspaniała wiadomość. Nawet jeżeli nie mamy ambicji wprowadzać własnych zmian, możemy na bieżąco śledzić rozwój platformy i podpatrywać jak to jest zrobione, do czego wszystkich zachęcam. Tomasz Pęczek Od 2006 roku zajmuje się projektowaniem i tworzeniem aplikacji webowych. W tym czasie pracował przy dużych projektach dla klientów takich jak NFZ, Centrum Monitorowania Jakości czy UBS. Obecnie pełni rolę Lead Software Engineer w firmie Oracle. Dodatkowo, od 2009 roku, zajmuje się projektami open sourcowymi. Swoją wiedzą i doświadczeniem dzieli się za pośrednictwem swojego bloga, a także na portalu Stack Overflow i licznych forach. Niektóre z jego artykułów trafiły do MSDN, Daily Community Spotlight na oficjalniej stronie ASP.NET oraz do This Week On Channel 9.Był także prelgentem na takich konferencjach jak MTS i 4Developers. www.sdjournal.pl 13

IL Weaving w służbie programiście Praca programisty to nie tylko ciekawe problemy, genialne algorytmy i zadowolenie użytkowników. To także tysiące linii kodu, które tworzymy każdego dnia, a które nierzadko nie stanowią funkcjonalności, a są częścią nudnego i powtarzalnego kodu infrastruktury naszych systemów i aplikacji. Jeśli kiedykolwiek zastanawialiście się jak można zautomatyzować część tej pracy, postaram się zaprezentować Wam jedno z rozwiązań. DOWIESZ SIĘ Czym jest IL Weaving i jak go wykorzystać, aby ułatwić sobie pracę i odchudzić kod aplikacji POWINIENEŚ WIEDZIEĆ Czym jest Intermediate Language oraz znać podstawy C# Dla dużej grupy programistów.net pojęcie MSIL (Microsoft Intermediate Language, a obecnie Common Intermediate Language) wywołuje dwie reakcje: Pobudzenie małego obszaru pamięci, która zawiera informacje o tym, że C# i VB.net (jak i inne języki zgodne Common Language Infrastructure) są kompilowane do postaci pośredniej, którą to właśnie jest IL Dziwny dreszcz na plecach, który przywodzi na myśl czasy studenckie i zmagania z Assemblerem. Co bardziej doświadczeni zdają sobie sprawę, że właśnie z faktu kompilacji pośredniej wynika możliwość korzystania z narzędzi typu Reflector i inżynierii odwrotnej (reverse engineering), co nie raz potrafi zaoszczędzić cenne godziny i ułatwia znalezienie źródła wrednego błędu. Ale jak wielu z nas potrafi skorzystać z IL do ułatwienia sobie codziennej pracy? Spróbuję pokazać Wam, jak możemy wykorzystać IL w służbie programiście i jak niedużym kosztem odchudzić nasz kod z nudnych, powtarzalnych fragmentów. Pojęcie IL Weaving (tkactwo?) coraz częściej pojawia się w środowisku.net. Liczba narzędzi i bibliotek, które usprawniają proces wciąż rośnie, a biorąc pod uwagę fakt wypuszczenia przez Microsoft platformy Roslyn, myślę że czeka nas prawdziwy wysyp wszelkiej maści usprawnień dla programistów. Ja dziś pozwolę sobie zaprezentować Wam troszkę mniej znaną bibliotekę o nazwie Afterthought, na którą to wpadłem dość przypadkowo przeglądając StackOverflow. Weaving O ile jak już wspomnieliśmy IL jest pojęciem znanym, to może parę słów wstępu dotyczącego drugiej części - weaving. Proces weaving u (z tego miejsca pragnę przeprosić wszystkich za korzystanie z angielskiej formy, niestety nie znam sensownie brzmiącego polskiego odpowiednika) polega na zmianie działania i rozbudowie funkcjonalności już istniejącej aplikacji. Możemy podejść do tego na dwa sposoby: Modyfikacja kodu źródłowego (source code weaving) Modyfikacja kodu pośredniego (IL weaving) Pierwsze podejście, to oczywiście nic innego jak edycja plików z kodem źródłowym jeszcze przed kompilacją. Drugie podejście jest dużo ciekawsze i (jak można się domyśleć) polega na modyfikacji naszej aplikacji na poziomie kodu pośredniego wygenerowanego w czasie kompilacji. Bo czemu mielibyśmy na przykład żmudnie wypisywać log.trace("<nazwa metody>") na początku każdej metody, skoro moglibyśmy to po prostu wstrzyknąć bezpośrednio do kodu IL? Zastanówmy się teraz, co musielibyśmy zrobić, aby rzeczywiście dokonać takiej modyfikacji: 1. Odczytujemy metadane z assembly 14 3/2014

IL Weaving 2. Dekodujemy ciąg instrukcji IL 3. Wyszukujemy wszystkie punkty, w których należy dokonać zmiany 4. Wstrzykujemy uprzednio przygotowane fragmenty IL do kodu 5. Zapisujemy zmiany z powrotem do pliku binarnego 6. Aktualizujemy pliki.pdb Nie wiem co Wy o tym myślicie, ale z mojego punktu widzenia to całkiem sporo pracy, która w dodatku nie wygląda na lekką, łatwą i przyjemną. Myślę, że w wielu projektach stosunek włożonej pracy, do osiągniętej korzyści byłby trudny do zaakceptowania. Różne podejścia Na szczęście nie zostaliśmy sami na tym polu i na rynku istnieje wiele narzędzi, które mniej lub bardziej pomagają nam w tym karkołomnym procesie. Spójrzmy na niektóre z nich PostSharp - chyba najbardziej znana biblioteka w temacie, pozwala wykorzystać siłę programowania aspektowego w.net. PostSharp udostępnia nam szereg punktów, do których możemy wstrzyknąć naszą logikę (przed/po wywołaniem metody, we właściwościach itd.) plus ciekawe funkcjonalności jak np. możliwość uruchomienia metody w tle za pomocą atrybytu. Na plus należy zaliczyć fakt, że piszemy tutaj po prostu w C# oraz obszerną, pełną przykładów dokumentację. Są i minusy, a jest nim moim zdaniem przede wszystkim to jak działa PostSharp na maszynie deweloperskiej. Wymaga on instalacji osobnej paczki i zdefiniowania kluczy dla każdego z programistów z osobna (nawet w okrojonej wersji darmowej). Dla zespołu pracującego w jednej firmie może nie jest to problem, ale jest wyraźnym utrudnieniem w środowisku OpenSource. Mono.Cecil - chyba najpopularniejsze rozwiązanie, jeśli chodzi o pracę bezpośrednio z IL. Biblioteka będąca częścią projektu Mono, udostępnia programistom API pozwalające na wczytanie i inspekcję assembly.net, jak również na wstrzykiwanie instrukcji IL. Cecil uwalnia programistę od koszmaru pracy z samymi binariami, formatem itd. pozwalając skupić się na samej funkcjonalności. Fody - ta nazwa coraz częściej pojawia się na blogach i w tweet ach. Fody buduje pewną abstrakcje nad Mono.Cecil, jeszcze bardziej ułatwiając pracę programiście. Koncepcja polega na tworzeniu wtyczek, które Fody sam aplikuje do odpowienich assembly. Niestety, podobnie jak w Mono.Cecil jesteśmy zmuszeni do korzystania bezpośrednio z instrukcji IL. Olbrzymią zaletą natomiast jest bardzo bogata (i wciąż rosnąca) biblioteka gotowych wtyczek. Jest bardzo prawdopodobne, że to czego po- trzebujecie, zostało już opracowane i wystarczy Nu- Get aby skorzystać z tego w projekcie. Afterthought - jest bohaterem tego artykułu. W założeniu, podobna do Fody biblioteka, która ma zdjąć jak najwięcej obowiązków z barków programisty i pozwolić mu skupić się na funkcjonalności. W przeciwieństwie do konkurenta, nie korzysta z Mono.Cecil, a z Common Compiler Infrastructure: Metadata API pochodzącego z Microsoftu, rozszerzenia piszemy w C#, nie IL. Kamery... AKCJA! Czas przejść od słów do czynów. Pokażę Wam jak uprzyjemnić sobie życie dzięki Afterthought na przykładzie aplikacji WPF. Zrzut okna możecie znaleźć poniżej. Aplikacja jest bardzo prosta, składa się z jednego przycisku, pola tekstowego i dwóch etykiet. Jak można się domyślić, po podaniu imienia i zatwierdzeniu przyciskiem, aplikacja powinna wyświetlić tekst Cześć, <imię>! (cały kod umieszczony jest w serwisie GitHub, odnośnik znajdziecie na końcu artykułu) - Efekt widoczny na Rysunku 1. Oczywiście aplikację tworzymy w duchu wzorca MVVM, także dla naszego widoku tworzymy klasę MainViewModel jak w Listingu 1. Rysunek 1. Okno aplikacji Listing 1. MainViewModel public class MainViewModel { public string Name { get; set; public string Result { get; set; private ICommand _getresultcommand; public ICommand GetResultCommand { get { return _getresultcommand?? (_getresultcommand = new RelayCommand(o => GetResult())); public void GetResult() { Result = String.Empty; if (!String.IsNullOrEmpty(Name)) { Result = String.Format( Cześć, {0!, Name); www.sdjournal.pl 15

Programiści zaznajomieni z WPF pewnie od razu zauważą, że w tym stanie aplikacja nie zadziała tak jak powinna - o ile wprowadzone w UI imię, zostanie przekazane do zmiennej Name, to zmiana zawartości zmiennej Result nie zostanie odzwierciedlona w interfejsie użytkownika, a ten nie poczuje się lepiej wiedząc, że aplikacja jest dobrze wychowana. Musimy zatem w jakiś sposób powiadomić UI o zmianie wartości Result i odświeżyć ekran. Służy do tego oczywiście interfejs INotifyPropertyChanged. W Listingu 2 znajdziemy wymagane zmiany klasy MainViewModel. Liczba linii wzrosła z 27, do 48 (ponad 50%!), ale za to mamy działającą aplikację. Efekt prezentuje Rysunek 2. Co prawda implementacji interfejsu musimy w tym przypadku dokonać tylko raz (a korzystając z prostej klasy bazowej, możemy ograniczyć się do jednej implementacji w całej aplikacji), o tyle korzystać z RaisePropertyChanged musimy już wszędzie, aby WPF wiedział, że wartość zmiennej uległa zmianie i należy odświeżyć UI. W tak prostym przykładzie nie jest to oczywiście problem, ale w dużych aplikacjach, z szeregiem formularzy, liczba niepotrzebnych linii kodu zaczyna szybko rosnąć (1 linia w auto-właściwości vs. 10 we właściwości z powiadomieniem). Rysunek 2. Działająca aplikacja Listing 2. MainViewModelNotify public class MainViewModel : INotifyPropertyChanged { public string Name { get; set; private string _result; public string Result { get { return _result; set { _result = value; RaisePropertyChanged( Result ); private ICommand _getresultcommand; public ICommand GetResultCommand { get { return _getresultcommand?? (_getresultcommand = new RelayCommand(o => GetResult())); public void GetResult() { Result = String.Empty; if (!String.IsNullOrEmpty(Name)) { Result = String.Format( Cześć, {0!, Name); public event PropertyChangedEventHandler PropertyChanged; private void RaisePropertyChanged(string propertyname) { var handler = PropertyChanged; if (handler!= null) { handler(this, new PropertyChangedEventArgs(propertyName)); Listing 3 INotifyPropertyChangedRaiser public interface INotifyPropertyChangedRaiser : INotifyPropertyChanged { void OnPropertyChanged(PropertyChangedEventArgs args); 16 3/2014

IL Weaving Tu z pomocą może przyjść właśnie Afterthought, który za nas wykona nudną i żmudną pracę. Do dzieła! Zaczynamy od pobrania źródeł projektu z GitHub. Otwieramy solucję i kompilujemy źródła. Interesują nas następujące pliki wynikowe: Afterthought.dll Afterthought.Amender.exe Afterthought.Amender.exe.config Kopiujemy je sobie do katalogu naszej solucji (np. Tools). Mamy już narzędzie, czas je wykorzystać i pokazać jak ma zmienić nasz kod wynikowy. Zaletą Afterthought jest fakt, że nie musi mieć on żadnego powiązania z kodem naszej aplikacji. Nie trzeba nawet dodawać referencji do biblioteki głównej. Potrzebujemy jedynie assembly, w którym zawrzemy kod modyfikujący. Stwórzmy zatem w solucji nowy projekt typu Class Library, posłuży nam on jako wtyczka dla Afterthought (ja nazwałem ją NotifyAmendment). Zacznijmy od interfejsu pośredniego, który udostępni metodę ułatwiającą wywołanie zdarzenia (Listing 3). Definicje naszych modyfikacji tworzymy w klasach dziedziczących z klasy Amendment<T,T> (referencja do Afterthought.dll). Parametr <T> zostanie w trakcie modyfikacji zastąpiony konkretnym, zmienianym typem. Drugie T, możemy użyć jeśli wiemy jakiego typu będzie nasza klasa wynikowa. W naszym przypadku, chcemy aby Listing 4. NotifyAmendment public class NotifyAmendment<T> : Amendment<T, INotifyPropertyChangedRaiser> { Listing 5. NotifyAmendmentImpl public NotifyAmendment() { //Dodajemy definicję zdarzenia, zadanego typu I nazwie var propertychanged = Events.Add<PropertyChangedEventHandler>( PropertyChanged ); // Implementujemy interfejs, przekazując listę elementów, które go implmentują. // W naszym przypadku jest to właśnie zdefiniowane zdarzenie propertychanged Implement<INotifyPropertyChanged>(propertyChanged); // definiujemy metodę o nazwie OnPropertyChanged, która zgłasza zdarzenie zdefiniowane // w zmiennej propertychanged var onchangemethod = Methods.Raise(propertyChanged, OnPropertyChanged ); // Implementujemy interfejs INotifyPropertyChanged, przekazując właśnie dodaną metodę // o nazwie OnPropertyChanged Implement<INotifyPropertyChangedRaiser>(onChangeMethod); // Ze wszystkich właściwości w modyfikowanym typie, znajdujemy te, które możemy odczytać i zapisać // oraz które mają publiczny setter. // Po setterze, wywołujemy zadany delegat (w tym przypadku ze statycznej klasy) Properties.Where(p => p.propertyinfo.canread && p.propertyinfo.canwrite && p.propertyinfo.getsetmethod(). IsPublic).AfterSet(RaisePropertyChangedHelper.RaisePropertyChanged); public static class RaisePropertyChangedHelper { /// <summary> /// Metoda pomocnicza która odpowiada delegatowi AfterSet. /// Dzięki takiej konstrukcji, nie doklejamy do naszej aplikacji klasy dziedziczącej z Amendement, /// a tym samym unikamy bezpośredniej zależności do Afterthought /// </summary> public static void RaisePropertyChanged<P>(INotifyPropertyChangedRaiser instance, string property, P oldvalue, P value, P newvalue) { // ten kod możemy urozmaicić np. sprawdzając, czy wartość rzeczywiście się zmieniła instance.onpropertychanged(new PropertyChangedEventArgs(property)); www.sdjournal.pl 17

implementowała ona zdefiniowany wcześniej interfejs INotifyPropertyChangedRaiser (Listing 4). W konstruktorze, decydujemy jakie zmiany chcemy wprowadzić (Listing 5). W tej chwili nasza klasa powinna być wzbogacona z zdarzenie o nazwie PropertyChanged oraz metodę OnPropertyChanged, która to zdarzenie zgłasza. Innymi słowy, mamy zaimplementowany interfejs INotifyPropertyChanged (zdarzenie) oraz metodę pomocniczą (OnPropertyChanged), a dla wszystkich publicznych właściwości, zaraz za setterem wywoływane jest nasze wyrażenie lambda, które wywołuje metodę OnPropertyChanged z odpowiednim parametrem. A wszystko to zupełnie bez naszego wysiłku. Brakuje jeszcze małego elementu w naszej układance. Afterthought pozwala nam dość łatwo określić do których elementów naszej aplikacji ma zastosować zmianę. Potrzebujemy w tym celu stworzyć atrybut, który dodatkowo implementuje interfejs IAmendmentAttribute i przypiąć go do biblioteki z definicjami zmian(w moim przypadku biblioteka Amendments). Tworzymy klasę NotifyAmendmentAttribute, zawartość klasy przedstawia Listing 6. Powyższy kod powoduje, że nasza zmiana zostanie wprowadzona dla każdej klasy, która nie implementuje Listing 6. NotifyAmendmentAttribute public class NotifyAmendmentAttribute : Attribute, IAmendmentAttribute { IEnumerable<ITypeAmendment> IAmendmentAttribute.GetAmendments(Type target) { if (target.getinterface( System.ComponentModel.INotifyPropertyChanged ) == null) yield return (ITypeAmendment)typeof(NotifyAmendment<>).MakeGenericType(target).GetConstructor(Type.EmptyTypes).Invoke(new object[0]); Listing 7. BatchVer01 xcopy NotifyAmendment\bin\Debug\NotifyAmendment.dll Gentleman\bin\Debug\ Tools\Afterthought.Amender.exe Gentleman\bin\Debug\Gentleman.exe NotifyAmendment\bin\Debug\ NotifyAmendment.dll Listing 8. TimerAmendment public class TimerAmendment<T> : Amendment<T, T> { public TimerAmendment() { Methods.Where(m => m.methodinfo.name == GetResult ).Before(Timer<T>.LogMethodBefore).After(Timer<T>.LogMethodAfter); public static class Timer<T> { private static readonly Dictionary<T, Stopwatch> _timers = new Dictionary<T, Stopwatch>(); public static void LogMethodBefore(T instance, string name, object[] ps) { _timers[instance] = Stopwatch.StartNew(); public static void LogMethodAfter(T instance, string name, object[] ps) { var stopwatch = _timers[instance]; stopwatch.stop(); Console.WriteLine( Czas wykonania: + stopwatch.elapsed); 18 3/2014

IL Weaving interfejsu INotifyPropertyChanged. Możemy oczywiście rozbudować te warunki, tworząc ciekawe i użyteczne konwencje w naszym projekcie (zgodnie z ideą convention over configuration ). Pozostaje tylko udekorować naszą bibliotekę ze zmianami właśnie stworzonym atrybutem. W tym celu w Assembly.cs dodajemy linijkę: [assembly: NotifyAmendment.NotifyAmendmentAttribute] Mamy zatem aplikację, mamy bibliotekę zawierającą definicję zmian jakich chcemy dokonać - czas połączyć to w całość. Na szczęście jest to wyjątkowo proste, nie trzeba żadnych instalatorów, ani wtyczek do Visual Studio. Mając skompilowane biblioteki i aplikację Amender, wystarczy ustawić odpowiednie Post build event. Osobiście, nie przepadam za tworzeniem rozbudowanych ciągów instrukcji w Post Build Event. Zdecydowanie przejrzyściej dla mnie, jest stworzyć plik wsadowy (.bat). Ułatwia on także testowanie. Stworzyłem plik Amend.bat w katalogu solucji. Zawartość przedstawia Listing 7. Teraz, we właściwości projektu naszej aplikacji, w zakładce Build Events, w polu Post build event command line wywołujemy : cd $(SolutionDir) Amend.bat Jednocześnie, naszą klasę ViewModelu możemy przywrócić do pierwszej wersji (czyli auto-właściwości i brak implememntacji INotifyPropertyChanged). Jeśli wszystko przebiegło poprawnie, naszym oczom powinno ukazać się w pełni działające okienko, które potrafi się z nami kulturalnie przywitać. I to bez narzutu zgłaszania zmian we właściwościach! Korzystając z narzędzia dotpeek, możemy teraz zajrzeć do naszego assembly i przekonać się, że rzeczywiście są tam implementacje potrzebnych interfejsów, a setter y wywołują zadane akcje. Fragment zaprezentowany na Rysunku 3. Instrumentacja kodu Chciałbym Wam pokazać jeszcze jedno zastosowanie Afterthought - instrumentację kodu, a na jej przykładzie jak obejść jedno z ograniczeń biblioteki. Afterthought ma bowiem dość dziwne założenie, otóż nie można dokonać modyfikacji tej samej klasy więcej niż raz. Nic nie stoi nam natomiast na przeszkodzie, aby uruchomić proces zmian po raz drugi. Zobaczmy jak mogłoby to wyglądać. Sama instrumentacja kodu, potrafi uprzyjemnić życie programiście zwłaszcza w okresie testowania systemu przez użytkowników (UAT). Mają oni bowiem nieograniczoną wyobraźnię, co często prowadzi do trudnych do odtworzenia błędów. Dzięki rozbudowanemu logowaniu zachowania aplikacji, wywoływanych metod, ich parametrów itp. możemy skrócić czas potrzebny Rysunek 3. Podgląd zmian IL w dotpeek www.sdjournal.pl 19

Rysunek 4. Wynik z konsoli Visual Studio na znalezienie źródła błędu, ale ilu z nas dodawanie do każdej metody wywołania logowania nazwałoby dobrą zabawą? Zautomatyzujmy zatem ten proces z wykorzystaniem Afterthought. W swojej solucji stworzyłem nowy projekt typu Class Library, który nazwałem TimerAmendment (w tym konkretnym przypadku, interesuje mnie czas wykonania metody). Zacznijmy od definicji zmian jakie chcemy wprowadzić. Tworzymy klasę TimerAmendment (Listing 8). Jak można się domyśleć, dla każdej z metod, których nazwa to "GetResult", wstrzykujemy kawałek kodu przed i po wywołaniu. Oczywiście jest to zbyt proste podejście do tematu (należałoby tu zadbać lepiej o przechowywanie stanu obiektów Stopwatch, chociażby dla środowisk wielowątkowych), ale ilustruje w jaki sposób możemy ułatwić sobie życie i uwolnić o niepotrzebnej, nudnej pracy. Potrzebujemy jeszcze atrybutu (pamiętajmy o dodaniu go do AssemblyInfo.cs) Listing 9. Pozostaje już tylko dodać naszą nową definicję do post build i cieszyć wynikami. Mój plik Amend.bat przedstawia Listing 10. Dwie instrukcje wymagają tu szerszego komentarza: Dodałem polecenie START /WAIT, aby instrukcje wykonały się po sobie Między kolejnymi zmianami, usuwam plik Gentleman.exe.afterthought. Afterthought w taki sposób oznacza już przetworzone assembly. Po tych zmianach i ponownym uruchomieniu aplikacji, możemy cieszyć się wynikami w konsoli, które zaprezentowane są na Rysunku 4. Rysunek 5. Instrumentacja widziana w programie dotpeek Listing 9. TimerAmendmentAttribute public class TimerAmendmentAttribute : Attribute, IAmendmentAttribute { IEnumerable<ITypeAmendment> IAmendmentAttribute.GetAmendments(Type target) { yield return (ITypeAmendment)typeof(TimerAmendment<>).MakeGenericType(target).GetConstructor(Type.EmptyTypes).Invoke(new object[0]); Listing 10. BatchVer02 xcopy NotifyAmendment\bin\Debug\NotifyAmendment.dll Gentleman\bin\Debug\ xcopy TimerAmendment\bin\Debug\TimerAmendment.dll Gentleman\bin\Debug\ START /WAIT Tools\Afterthought.Amender.exe Gentleman\bin\Debug\Gentleman.exe NotifyAmendment\bin\ Debug\NotifyAmendment.dll rm Gentleman\bin\Debug\Gentleman.exe.afterthought Tools\Afterthought.Amender.exe Gentleman\bin\Debug\Gentleman.exe TimerAmendment\bin\Debug\ TimerAmendment.dll 20 3/2014