Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00287 007778 11009280 na godz. na dobę w sumie
C# 5.0. Programowanie. Tworzenie aplikacji Windows 8, internetowych oraz biurowych w .NET 4.5 Framework - książka
C# 5.0. Programowanie. Tworzenie aplikacji Windows 8, internetowych oraz biurowych w .NET 4.5 Framework - książka
Autor: Liczba stron: 840
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-246-6984-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c# - programowanie
Porównaj ceny (książka, ebook, audiobook).

Najlepszy podręcznik poświęcony C#!

W dzisiejszych czasach szczególną popularnością cieszą się języki programowania pozwalające na pisanie kodu łatwego do przenoszenia między platformami. Nikt nie ma czasu na pisanie kilku wersji jednej aplikacji. C# to uniwersalny język, w którym bez trudu dokonasz tego dzieła. Dzięki swej elastyczności, wydajności oraz mocnemu wsparciu społeczności zdobył on uznanie programistów. Taki wybór to strzał w dziesiątkę!

Ten rewelacyjny podręcznik jest Twoim kluczem do poznania wszystkich niuansów języka C# 5.0. Kolejne wydanie zostało zaktualizowane o wszystkie nowości w C#. Znajdziesz tu kompletny opis języka i platformy .NET. W trakcie lektury oprócz standardowych zagadnień będziesz mógł sprawdzić, jak tworzyć aplikacje dla systemu Windows 8 i interfejsu Metro. Ponadto błyskawicznie opanujesz detale związane z programowaniem obiektowym, dynamicznym i statycznym określaniem typów oraz językiem XAML. Książka ta jest uznanym kompendium wiedzy na temat języka C#. Musisz ją mieć!

Dzięki tej książce:

Wykorzystaj potencjał języka C#!

 


 

Ian Griffiths jest autorem kursu WPF oraz instruktorem w firmie Pluralsight, specjalizującej się w prowadzeniu kursów Microsoft .NET. Pracuje także jako niezależny konsultant. Jest współautorem książek „Windows Forms in a Nutshell”, „Mastering Visual Studio .NET” oraz „Programming WPF”, wydanych przez wydawnictwo O’Reilly.



Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Programming C# 5.0 Tłumaczenie: Piotr Rajca ISBN: 978-83-246-6984-4 © 2013 Helion S.A. Authorized Polish translation of the English edition Programming C# 5.0 ISBN 9781449320416 © 2013 Ian Griffiths. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Wydawnictwo HELION dołożyło wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/csh5pr Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/csh5pr.zip Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis treļci Wstýp .......................................................................................................................................17 Dlaczego C#? Dlaczego nie C#? NajwaĔniejsze cechy C# Kod zarzñdzany i CLR OgólnoĈè jest waĔniejsza od specjalizacji Programowanie asynchroniczne 1. Prezentacja C# ............................................................................................................. 21 21 23 25 27 29 30 31 33 35 35 37 40 44 44 45 47 Dodawanie projektów do istniejñcej solucji Odwoäania do innych projektów Pisanie testu jednostkowego Przestrzenie nazw Klasy Punkt wejĈcia do programu Testy jednostkowe Visual Studio Anatomia prostego programu Podsumowanie Zmienne lokalne Zakres Instrukcje WyraĔenia Instrukcje i wyraĔenia 2. Podstawy stosowania jýzyka C# ................................................................................49 50 55 58 59 60 65 67 67 68 69 69 70 Symbole kompilacji Dyrektywy #error oraz #warning Dyrektywa #line Dyrektywa #pragma Dyrektywy #region i #endregion Komentarze i biaäe znaki Dyrektywy preprocesora 5 Poleć książkęKup książkę Wbudowane typy danych Typy liczbowe WartoĈci logiczne Znaki i äaþcuchy znaków Object Operatory Sterowanie przepäywem Decyzje logiczne przy uĔyciu instrukcji if Wielokrotny wybór przy uĔyciu instrukcji switch Pötle: while oraz do Pötle znane z jözyka C Przeglñdanie kolekcji przy uĔyciu pötli foreach Podsumowanie 70 71 80 80 81 81 87 87 89 91 92 93 94 Klasy Struktury Skäadowe Kiedy tworzyè typy wartoĈciowe? Skäadowe statyczne Klasy statyczne Typy referencyjne 3. Typy ..............................................................................................................................95 95 98 100 101 106 110 115 115 117 125 130 134 135 138 138 140 141 144 145 146 147 Pola Konstruktory Metody WäaĈciwoĈci Indeksatory Operatory Zdarzenia Typy zagnieĔdĔone Interfejsy Typy wyliczeniowe Inne typy Typy anonimowe Typy i metody czöĈciowe Podsumowanie Typy ogólne Ograniczenia 4. Typy ogólne ................................................................................................................ 149 150 152 153 155 157 158 Ograniczenia typu Ograniczenia typu referencyjnego Ograniczenia typu wartoĈciowego Stosowanie wielu ograniczeþ 6 _ Spis treļci Poleć książkęKup książkę WartoĈci przypominajñce zero Metody ogólne Wnioskowanie typu Tajniki typów ogólnych Podsumowanie 158 160 160 161 163 5. Kolekcje ...................................................................................................................... 165 165 168 Inicjalizacja tablic UĔycie säowa kluczowego params do przekazywania Tablice zmiennej liczby argumentów Przeszukiwanie i sortowanie Tablice wielowymiarowe Kopiowanie i zmiana wielkoĈci List T Interfejsy list i sekwencji Implementacja list i sekwencji Iteratory Klasa Collection T Klasa ReadOnlyCollection T Säowniki Säowniki posortowane Zbiory Kolejki i stosy Listy poäñczone Kolekcje wspóäbieĔne Krotki Podsumowanie 169 171 178 181 182 185 189 190 194 195 196 198 200 201 202 203 204 205 Kowariancja i kontrawariancja System.Object Wszechobecne metody typu object Dziedziczenie i konwersje Dziedziczenie interfejsów Typy ogólne 6. Dziedziczenie .............................................................................................................207 208 210 211 212 217 217 218 220 222 228 229 230 234 235 Metody i klasy ostateczne Dostöp do skäadowych klas bazowych Dziedziczenie i tworzenie obiektów Specjalne typy bazowe Podsumowanie DostöpnoĈè i dziedziczenie Metody wirtualne Metody abstrakcyjne Spis treļci _ 7 Poleć książkęKup książkę Mechanizm odzyskiwania pamiöci OkreĈlanie osiñgalnoĈci danych Przypadkowe problemy mechanizmu odzyskiwania pamiöci Säabe referencje Odzyskiwanie pamiöci Tryby odzyskiwania pamiöci Przypadkowe utrudnianie scalania Wymuszanie odzyskiwania pamiöci 7. Cykl Ŝycia obiektów ...................................................................................................237 238 239 242 244 248 254 256 260 261 264 265 271 272 276 277 Pakowanie danych typu Nullable T Destruktory i finalizacja Zwalnianie opcjonalne Finalizatory krytyczne Interfejs IDisposable Podsumowanie Pakowanie đródäa wyjñtków Zgäaszanie wyjñtków Typy wyjñtków Obsäuga wyjñtków Obiekty wyjñtków Wiele bloków catch ZagnieĔdĔone bloki try Bloki finally Wyjñtki zgäaszane przez API Wyjñtki w naszym kodzie Bäödy wykrywane przez Ĉrodowisko uruchomieniowe 8. Wyjétki .......................................................................................................................279 281 282 284 284 285 286 287 289 290 292 292 295 296 298 301 303 305 308 Powtórne zgäaszanie wyjñtków Sposób na szybkie zakoþczenie aplikacji Wyjñtki asynchroniczne Podsumowanie Wyjñtki niestandardowe Wyjñtki nieobsäugiwane Debugowanie i wyjñtki Typy delegatów 9. Delegaty, wyraŜenia lambda i zdarzenia .................................................................309 310 311 314 316 318 319 323 Tworzenie delegatów MulticastDelegate — delegaty zbiorowe Wywoäywanie delegatów Popularne typy delegatów ZgodnoĈè typów Wiöcej niĔ skäadnia 8 _ Spis treļci Poleć książkęKup książkę Metody inline Przechwytywane zmienne WyraĔenia lambda oraz drzewa wyraĔeþ Zdarzenia Standardowy wzorzec delegatów zdarzeþ Niestandardowe metody dodajñce i usuwajñce zdarzenia Zdarzenia i mechanizm odzyskiwania pamiöci Zdarzenia a delegaty Delegaty a interfejsy Podsumowanie 326 328 335 336 338 339 342 344 345 345 WyraĔenia zapytaþ Jak sñ rozwijane wyraĔenia zapytaþ Obsäuga wyraĔeþ zapytaþ Przetwarzanie opóĒnione LINQ, typy ogólne oraz interfejs IQueryable T Standardowe operatory LINQ Filtrowanie Selekcja Operator SelectMany OkreĈlanie porzñdku Testy zawierania Konkretne elementy i podzakresy Agregacja Operacje na zbiorach Operatory dziaäajñce na caäych sekwencjach z zachowaniem kolejnoĈci Grupowanie Zäñczenia Konwersje 10. LINQ ............................................................................................................................347 348 351 353 357 359 361 364 366 369 371 373 375 379 384 384 386 390 392 396 397 397 398 398 399 399 399 400 Generowanie sekwencji Inne implementacje LINQ Entity Framework LINQ to SQL Klient WCF Data Services Parallel LINQ (PLINQ) LINQ to XML Reactive Extensions Podsumowanie 11. Reactive Extensions ................................................................................................... 401 403 405 406 407 Rx oraz róĔne wersje .NET Framework Podstawowe interfejsy Interfejs IObserver T Interfejs IObservable T Spis treļci _ 9 Poleć książkęKup książkę Publikowanie i subskrypcja z wykorzystaniem delegatów Tworzenie Ēródäa przy wykorzystaniu delegatów Subskrybowanie obserwowalnych Ēródeä przy uĔyciu delegatów Generator sekwencji Empty Never Return Throw Range Repeat Generate Zapytania LINQ Operatory grupowania Operatory Join Operator SelectMany Agregacja oraz inne operatory zwracajñce jednñ wartoĈè Operator Concat Operatory biblioteki Rx Merge Operatory Buffer i Window Operator Scan Operator Amb DistinctUntilChanged Mechanizmy szeregujñce OkreĈlanie mechanizmów szeregujñcych Wbudowane mechanizmy szeregujñce Tematy Subject T BehaviorSubject T ReplaySubject T AsyncSubject T Dostosowanie IEnumerable T Zdarzenia .NET API asynchroniczne Operacje z uzaleĔnieniami czasowymi Interval Timer Timestamp TimeInterval Throttle Sample Timeout Operatory okien czasowych Delay DelaySubscription Podsumowanie 10 _ Spis treļci 413 413 417 418 418 418 419 419 419 419 420 421 423 424 429 430 431 431 432 433 440 441 442 442 443 445 447 447 448 449 449 450 450 452 454 456 456 457 458 459 459 460 460 460 461 461 462 Poleć książkęKup książkę Jawne wczytywanie podzespoäów Global Assembly Cache Nazwy podzespoäów ToĔsamoĈè typu Wczytywanie podzespoäów Metadane .NET Zasoby Podzespoäy skäadajñce siö z wielu plików Inne moĔliwoĈci formatu PE 12. Podzespoĥy .................................................................................................................463 463 464 465 465 466 467 468 471 473 474 476 476 480 484 487 488 490 490 491 492 493 494 Aplikacje dla systemu Windows 8 ClickOnce oraz XBAP Aplikacje Silverlight oraz Windows Phone Silne nazwy Numer wersji Identyfikator kulturowy Architektura procesora Visual Studio i podzespoäy Anatomia podzespoäu PrzenoĈne biblioteki klas WdraĔanie pakietów Zabezpieczenia Podsumowanie Typy odzwierciedlania 13. Odzwierciedlanie .......................................................................................................495 495 498 502 503 506 510 512 513 513 514 514 516 Assembly Module MemberInfo Type oraz TypeInfo MethodBase, ConstructorInfo oraz MethodInfo ParameterInfo FieldInfo PropertyInfo EventInfo Konteksty odzwierciedlania Podsumowanie Typ dynamic Säowo kluczowe dynamic i mechanizmy wspóädziaäania 14. Dynamiczne okreļlanie typów ...................................................................................517 519 521 524 525 Silverlight i obiekty skryptowe Dynamiczne jözyki .NET Spis treļci _ 11 Poleć książkęKup książkę Tajniki typu dynamic Ograniczenia typu dynamic Niestandardowe obiekty dynamiczne Klasa ExpandoObject Ograniczenia typu dynamic Podsumowanie 526 526 528 531 531 534 Stosowanie atrybutów Cele atrybutów Atrybuty obsäugiwane przez kompilator Atrybuty obsäugiwane przez CLR 15. Atrybuty .....................................................................................................................535 535 537 539 543 551 551 553 556 Definiowanie i stosowanie atrybutów niestandardowych Typ atrybutu Pobieranie atrybutów Podsumowanie Klasa Stream Windows 8 oraz interfejs IRandomAccessStream Typy operujñce na tekstach PoäoĔenie i poruszanie siö w strumieniu OpróĔnianie strumienia Kopiowanie Length Zwalnianie strumieni Operacje asynchroniczne Konkretne typy strumieni 16. Pliki i strumienie ........................................................................................................557 558 560 561 562 562 564 565 565 566 569 570 572 574 578 578 581 585 586 588 589 590 590 591 594 597 598 Klasa FileStream Klasa File Klasa Directory Klasa Path Klasy FileInfo, DirectoryInfo oraz FileSystemInfo Znane katalogi TextReader oraz TextWriter Konkretne typy do odczytu i zapisu äaþcuchów znaków Kodowanie Pliki i katalogi Klasy BinaryReader oraz BinaryWriter Serializacja CLR Serializacja kontraktu danych Klasa XmlSerializer Serializacja Podsumowanie 12 _ Spis treļci Poleć książkęKup książkę Wñtki Zadania Synchronizacja Wñtki, zmienne i wspólny stan Klasa Thread Pula wñtków Powinowactwo do wñtku oraz klasa SynchronizationContext Monitory oraz säowo kluczowe lock Klasa SpinLock Blokady odczytu i zapisu Obiekty zdarzeþ Klasa Barrier Klasa CountdownEvent Semafory Muteksy Klasa Interlocked Leniwa inicjalizacja Pozostaäe klasy obsäugujñce dziaäania wspóäbieĔne 17. Wielowétkowoļë .......................................................................................................599 599 601 607 609 614 618 619 625 627 628 631 632 632 633 634 637 639 640 640 643 645 647 648 649 650 651 652 653 653 654 654 655 Klasy Task oraz Task T Kontynuacje Mechanizmy szeregujñce Obsäuga bäödów Niestandardowe zadania bezwñtkowe Zwiñzki zadanie nadrzödne — zadanie podrzödne Zadania zäoĔone Inne wzorce asynchroniczne Anulowanie RównolegäoĈè Klasa Parallel Parallel LINQ TPL Dataflow Podsumowanie Nowe säowa kluczowe: async oraz await Konteksty wykonania i synchronizacji Wykonywanie wielu operacji i pötli Zwracanie obiektu Task Stosowanie async w metodach zagnieĔdĔonych 18. Asynchroniczne cechy jýzyka ....................................................................................657 658 662 663 666 667 668 672 674 675 677 678 Weryfikacja poprawnoĈci argumentów Wyjñtki pojedyncze oraz grupy wyjñtków Operacje równolegäe i nieobsäuĔone wyjñtki Wzorzec säowa kluczowego await Obsäuga bäödów Podsumowanie Spis treļci _ 13 Poleć książkęKup książkę Platformy XAML 19. XAML .......................................................................................................................... 681 682 683 684 686 WPF Silverlight Windows Phone 7 Windows Runtime oraz aplikacje dostosowane do interfejsu uĔytkownika Windows 8 Podstawy XAML Przestrzenie nazw XAML oraz XML Generowane klasy i kod ukryty Elementy podrzödne Elementy wäaĈciwoĈci Obsäuga zdarzeþ Wykorzystanie wñtków Ukäad WäaĈciwoĈci Panele ScrollViewer Zdarzenia zwiñzane z ukäadem Kontrolki Kontrolki z zawartoĈciñ Kontrolki Slider oraz ScrollBar Kontrolki postöpów Listy Szablony kontrolek Kontrolki uĔytkownika Tekst WyĈwietlanie tekstów Edycja tekstów Wiñzanie danych Szablony danych Grafika Ksztaäty Bitmapy Media Style Podsumowanie 687 688 689 690 692 692 694 695 696 696 702 712 712 713 714 717 718 719 721 724 725 725 727 729 732 735 735 736 737 738 739 Razor 20. ASP.NET ...................................................................................................................... 741 742 743 745 746 747 748 749 WyraĔenia Sterowanie przepäywem Bloki kodu Jawne wskazywanie treĈci Klasy i obiekty stron Stosowanie innych komponentów 14 _ Spis treļci Poleć książkęKup książkę Strony ukäadu Strony poczñtkowe Web Forms Kontrolki serwerowe WyraĔenia Bloki kodu Standardowe obiekty stron Klasy i obiekty stron Stosowanie innych komponentów Strony nadrzödne MVC Typowy ukäad projektu MVC Pisanie modeli Pisanie widoków Pisanie kontrolerów Obsäuga dodatkowych danych wejĈciowych Generowanie äñczy do akcji Trasowanie Podsumowanie 749 751 752 752 758 758 759 759 760 760 762 763 769 771 772 774 776 777 781 Wywoäywanie kodu rodzimego Szeregowanie Procesy 32- i 64-bitowe Bezpieczne uchwyty Bezpieczeþstwo Konwencje wywoäaþ Obsäuga äaþcuchów znaków Nazwa punktu wejĈcia WartoĈci wynikowe technologii COM Obsäuga bäödów Win32 21. Wspóĥdziaĥanie ..........................................................................................................783 783 784 792 793 794 795 796 797 797 798 802 802 803 805 811 814 815 815 816 818 819 820 Niebezpieczny kod C++/CLI i Component Extensions Podsumowanie Mechanizm Platform Invoke Technologia COM Czas Ĕycia obiektów RCW Metadane Skrypty Windows Runtime Metadane Typy Windows Runtime Bufory Skorowidz ............................................................................................................................. 821 Spis treļci _ 15 Poleć książkęKup książkę 16 _ Spis treļci Poleć książkęKup książkę ROZDZIAĤ 18. Asynchroniczne cechy jýzyka Podstawowñ nowoĈciñ wprowadzonñ w C# 5.0 jest wsparcie jözyka dla stosowania i implementa- cji metod asynchronicznych. Metody asynchroniczne sñ niejednokrotnie najbardziej wydajnym sposobem korzystania z niektórych usäug. Na przykäad wiökszoĈè operacji wejĈcia-wyjĈcia jest wykonywana asynchronicznie przez jñdro systemu operacyjnego, gdyĔ wiökszoĈè urzñ- dzeþ peryferyjnych, takich jak kontrolery dysków lub karty sieciowe, jest w stanie wykonywaè wiökszoĈè operacji autonomicznie. Wymagajñ uĔycia procesora wyäñcznie podczas rozpoczy- nania i zakaþczania operacji. Choè wiele usäug dostarczanych przez system Windows ma w rzeczywistoĈci asynchroniczny charakter, to jednak programiĈci czösto decydujñ siö na korzystanie z nich przy uĔyciu metod synchronicznych (czyli takich, które koþczñ siö przed wykonaniem tego, co miaäy zrobiè). Jednak takie postöpowanie jest marnowaniem zasobów, gdyĔ powoduje ono zablokowanie wñtku aĔ do momentu zakoþczenia operacji wejĈcia-wyjĈcia. W systemie Windows wñtki sñ cennym zasobem, dlatego teĔ uzyskuje on najwyĔszñ wydajnoĈè, gdy liczba dziaäajñcych w nim wñtków systemowych jest stosunkowo niewielka. W idealnym przypadku liczba wñtków systemowych bödzie odpowiadaè liczbie wñtków sprzötowych, lecz jest to przypadek opty- malny, wyäñcznie jeĈli moĔemy zagwarantowaè, Ĕe wñtki bödñ blokowane tylko w sytuacjach, gdy nie majñ Ĕadnych innych prac do wykonania. (RóĔnice pomiödzy wñtkami systemowymi oraz wñtkami sprzötowymi zostaäy wyjaĈnione w rozdziale 17.) Im wiöcej wñtków bödzie blokowanych w wywoäaniach metod synchronicznych, tym wiöcej bödziemy potrzebowali wñtków do obsäugi obciñĔenia, a to z kolei prowadzi do ograniczenia wydajnoĈci. Dlatego teĔ w kodzie, w którym wydajnoĈè dziaäania odgrywa bardzo duĔñ rolö, metody asynchroniczne sñ uĔyteczne, gdyĔ zamiast marnowaè zasoby poprzez zmuszanie wñtku do oczekiwania na zakoþczenie operacji wejĈcia-wyjĈcia, wñtek moĔe zainicjowaè takñ operacjö, a nastöpnie w miödzyczasie zajñè siö czymĈ innym. Jednak problem z metodami asynchronicznymi polega na tym, Ĕe ich stosowanie jest znaczñ- co bardziej zäoĔone od korzystania z metod synchronicznych, zwäaszcza kiedy w grö wcho- dzi koordynacja wielu powiñzanych ze sobñ operacji oraz obsäuga bäödów. To wäaĈnie z tego powodu programiĈci bardzo czösto wybierajñ mniej wydajne, synchroniczne rozwiñzania. Jednak nowe, asynchroniczne moĔliwoĈci jözyka C# 5.0 pozwalajñ na tworzenie kodu, który moĔe korzystaè z wydajnych, asynchronicznych API, zachowujñc przy tym jednoczeĈnie znacznñ czöĈè prostoty cechujñcej kod uĔywajñcy prostszych rozwiñzaþ synchronicznych. 657 Poleć książkęKup książkę Nowe moĔliwoĈci jözyka przydajñ siö takĔe w niektórych przypadkach, gdy gäównym celem zapewnienia wydajnoĈci dziaäania nie jest maksymalizacja przepustowoĈci. W przypadku kodu aplikacji klienckich bardzo waĔnym zagadnieniem jest unikanie blokowania wñtku obsäugi in- terfejsu uĔytkownika, a jednym z rozwiñzaþ jest stosowanie metod asynchronicznych. Wsparcie dla kodu asynchronicznego, jakie zapewnia C#, jest w stanie obsäugiwaè problemy zwiñzane z powinowactwem do wñtku, co w ogromnym stopniu uäatwia tworzenie kodu obsäugi interfejsu uĔytkownika zapewniajñcego bäyskawicznñ reakcjö na poczynania uĔytkownika aplikacji. Nowe sĥowa kluczowe: async oraz await C# udostöpnia wsparcie dla programowania asynchronicznego, wprowadzajñc dwa säowa kluczowe: async oraz await. Pierwsze z nich nie jest przeznaczone do samodzielnego uĔycia. Umieszcza siö je natomiast w deklaracjach metod, a jego zadaniem jest poinformowanie kompilatora, Ĕe w metodzie bödñ uĔywane moĔliwoĈci asynchroniczne. JeĈli säowo to nie zo- stanie umieszczone w deklaracji metody, to nie bödzie jej moĔna uĔywaè wraz ze säowem kluczowym await. Jest to prawdopodobnie nieco nadmiarowe — kompilator zgäasza bäñd, jeĈli spróbujemy uĔyè säowa kluczowego await bez async, czyli najwyraĒniej jest w stanie okre- Ĉliè, czy ciaäo metody próbuje korzystaè z moĔliwoĈci asynchronicznych. A zatem dlaczego musimy jawnie deklarowaè asynchronicznoĈè metody? OtóĔ wynika to z dwóch powodów. Przede wszystkim, jak siö niebawem przekonasz, te moĔliwoĈci drastycznie zmieniajñ za- chowanie kodu generowanego przez kompilator, dlatego teĔ stanowi to wyraĒny sygnaä in- formujñcy wszystkie osoby przeglñdajñce kod, Ĕe metoda dziaäa w sposób asynchroniczny. A poza tym säowo await nie zawsze byäo säowem kluczowym jözyka C#, zatem wczeĈniej nic nie staäo na przeszkodzie, by uĔywaè go jako identyfikatora. Byè moĔe firma Microsoft mogäa zaprojektowaè gramatykö säowa await w taki sposób, by byäo ono traktowane jako säowo kluczowe wyäñcznie w bardzo specyficznych kontekstach, dziöki czemu we wszystkich innych przypadkach mogäoby wciñĔ byè traktowane jako zwyczajny identyfikator. Niemniej jednak twórcy jözyka C# zdecydowali siö zastosowaè nieco bardziej ogólne podejĈcie: otóĔ säowa await nie moĔna uĔywaè jako identyfikatora wewnñtrz metod, w których deklaracji zasto- sowano modyfikator async, natomiast we wszystkich pozostaäych miejscach kodu moĔe ono säuĔyè za identyfikator. Säowo kluczowe async nie zmienia sygnatury metody. Determinuje ono sposób kompilacji metody, a nie jej uĔywania. A zatem modyfikator async jedynie deklaruje chöè uĔywania säowa kluczowego await. (Choè nie wolno nam uĔywaè säowa kluczowego await bez async, to jednak nie jest bäödem umiesz- czanie modyfikatora async w deklaracji metody, która nie wykorzystuje säowa kluczowego await. Niemniej jednak takie rozwiñzanie nie ma Ĕadnego sensu, dlatego teĔ jeĈli wystñpi, kompilator wygeneruje ostrzeĔenie). Listing 18.1 przedstawia dosyè typowy przykäad metody asynchronicznej. UĔywa ona klasy HttpClient1, by poprosiè jedynie o nagäówki konkretnego zasobu (uĔywajñc w tym celu standardowego Ĕñdania HEAD, które istnieje w protokole HTTP 1 Zostaäa ona tutaj zastosowana zamiast prostszej klasy WebClient, której uĔywaliĈmy w przykäadach przed- stawianych w poprzednich rozdziaäach, gdyĔ zapewnia wiökszñ kontrolö nad szczegóäami wykorzystania protokoäu HTTP. 658 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę wäaĈnie do tego celu). Uzyskane wynik sñ nastöpnie wyĈwietlane w polu tekstowym stano- wiñcym element interfejsu uĔytkownika aplikacji — metoda ta stanowi fragment kodu ukry- tego, obsäugujñcego interfejs uĔytkownika aplikacji, który zawiera pole TextBox o nazwie headerListTextBox. Listing 18.1. Stosowanie säów kluczowych async i await podczas pobierania nagäówków HTTP private async void FetchAndShowHeaders(string url) { using (var w = new HttpClient()) { var req = new HttpRequestMessage(HttpMethod.Head, url); HttpResponseMessage response = await w.SendAsync(req, HttpCompletionOption.ResponseHeadersRead); var headerStrings = from header in response.Headers select header.Key + : + string.Join( , , header.Value); string headerList = string.Join(Environment.NewLine, headerStrings); headerListTextBox.Text = headerList; } } PowyĔszy kod zawiera jedno wyraĔenie uĔywajñce säowa kluczowego await, które zostaäo wyróĔnione pogrubionñ czcionkñ. Säowo to jest uĔywane w wyraĔeniach, które mogñ byè wykonywane przez däuĔszy czas, zanim zwrócñ wynik; oznacza ono, Ĕe dalsza czöĈè metody nie powinna byè wykonana, dopóki operacja siö nie zakoþczy. Wyglñda to zatem jak zwy- czajny, blokujñcy kod synchroniczny, jednak róĔnica polega na tym, Ĕe säowo kluczowe await nie powoduje zablokowania wñtku. GdybyĈmy chcieli zablokowaè wñtek i poczekaè na wyniki, to nic nie stoi na przeszkodzie, by to zrobiè. Metoda SendAsync klasy HttpClient zwraca obiekt Task HttpResponseMessage , wiöc moĔna by zastñpiè wyraĔenie z listingu 18.1 uĔywajñce säowa kluczowego await wy- raĔeniem przedstawiony na listingu 18.2. Pobiera ono wartoĈè wäaĈciwoĈci Result zadania, a zgodnie z tym, czego dowiedzieliĈmy siö w rozdziale 17., jeĈli zadanie nie zostaäo zakoþ- czone, to próba odczytu tej wäaĈciwoĈci spowoduje zablokowanie wñtku do czasu wyge- nerowania wyników (bñdĒ do momentu, gdy zadanie zakoþczy siö niepowodzeniem, lecz w takim przypadku wyraĔenie zgäosi wyjñtek). Listing 18.2. Blokujñcy odpowiednik wyraĔenia ze säowem kluczowym await HttpResponseMessage response = w.SendAsync(req, HttpCompletionOption.ResponseHeadersRead).Result; Choè wyraĔenie await zastosowane w kodzie z listingu 18.1 robi coĈ, co jest pozornie po- dobne do powyĔszej instrukcji, to jednak dziaäa zupeänie inaczej. JeĈli wynik zadania nie bö- dzie dostöpny od razu, to niezaleĔnie od tego, co sugeruje jego nazwa, säowo kluczowe await sprawi, Ĕe wñtek bödzie czekaä. Zamiast tego spowoduje ono zakoþczenie wykonywanej metody. MoĔna uĔyè debugera, by przekonaè siö, Ĕe wywoäanie metody FetchAdnShowHeaders koþczy siö natychmiast. Na przykäad: jeĈli wywoäamy tö metodö w procedurze obsäugi klikniöcia przy- cisku, przedstawionej na listingu 18.3, to moĔemy ustawiè jeden punkt przerwania w wierszu zawierajñcym wywoäanie Debug.WriteLine, oraz drugi w kodzie z listingu 18.1, w wierszu zawierajñcym instrukcjö aktualizujñcñ wartoĈè wäaĈciwoĈci headerListTextBox.Text. Nowe sĥowa kluczowe: async oraz await _ 659 Poleć książkęKup książkę Listing 18.3. Wywoäywanie metody asynchronicznej private void fetchHeadersButton_Click(object sender, RoutedEventArgs e) { FetchAndShowHeaders( http://helion.pl/ ); Debug.WriteLine( WywoĪanie metody zostaĪo zakoĬczone. ); } JeĈli uruchomimy taki program w debugerze, przekonamy siö, Ĕe najpierw zatrzymamy siö w punkcie przerwania umieszczonym w wierszu z listingu 18.3, a dopiero póĒniej w punkcie przerwania z listingu 18.1. Innymi säowy, fragment kodu z listingu 18.1 umieszczony za wy- raĔeniem ze säowem kluczowym await zostaje wykonany po tym, gdy sterowanie zostanie przekazane z metody do kodu, który jñ wywoäaä. NajwyraĒniej kompilator jakoĈ zmienia dal- szñ czöĈè metody w taki sposób, aby zostaäa wykonana przy uĔyciu wywoäania zwrotnego, realizowanego po zakoþczeniu operacji asynchronicznej. Debuger Visual Studio stosuje róĔne sztuczki podczas debugowania metod asynchro- nicznych, aby zapewniè nam moĔliwoĈè analizowania ich krok po kroku jak normalnych metod. Zazwyczaj jest to caäkiem przydatne, jednak czasami ukrywa prawdziwy prze- bieg realizacji programu. Opisany powyĔej przykäad zostaä uwaĔnie zaprojektowany w taki sposób, aby przekreĈliè starania Visual Studio i pokazaè faktyczny sposób re- alizacji kodu. Warto zauwaĔyè, Ĕe kod z listingu 18.1 oczekuje, Ĕe bödzie wykonywany w wñtku obsäugi interfejsu uĔytkownika, gdyĔ pod koniec metody modyfikuje wartoĈè wäaĈciwoĈci Text pola tekstowego. Metody asynchroniczne nie dajñ gwarancji, Ĕe powiadomienia o zakoþczeniu operacji bödñ generowane w tym samym wñtku, w którym operacja zostaäa rozpoczöta — w wiökszoĈci przypadków bödñ one generowane w innych wñtkach. Pomimo to kod z listingu 18.1 dziaäa zgodnie z zamierzeniami. Oznacza to, Ĕe säowo kluczowe await nie tylko spowo- dowaäo przeniesienie poäowy kodu metody do wywoäania zwrotnego, lecz takĔe zadbaäo za nas o prawidäowñ obsäugö powinowactwa do wñtku. To wszystko wyraĒnie pokazuje, Ĕe uĔycie säowa kluczowego await zmusza kompilator do przeprowadzenia drastycznych zmian w naszym kodzie. W C# 4.0, chcñc uĔyè tego asyn- chronicznego API, a nastöpnie zaktualizowaè interfejs uĔytkownika, konieczne byäo zastoso- wanie kodu podobnego do tego z listingu 18.4. Wykorzystuje on technikö opisanñ w roz- dziale 17.: przygotowuje kontynuacjö dla zadania zwróconego przez metodö SendAsync, wykorzystujñc przy tym obiekt TaskScheduler, by zapewniè, Ĕe kod kontynuacji zostanie wykonany w wñtku obsäugi interfejsu uĔytkownika. Listing 18.4. Samodzielne tworzenie odpowiednika metody asynchronicznej private void OldSchoolFetchHeaders(string url) { var w = new HttpClient(); var req = new HttpRequestMessage(HttpMethod.Head, url); var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); w.SendAsync(req, HttpCompletionOption.ResponseHeadersRead) .ContinueWith(sendTask = { try { HttpResponseMessage response = sendTask.Result; 660 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę var headerStrings = from header in response.Headers select header.Key + : + string.Join( , , header.Value); string headerList = string.Join(Environment.NewLine, headerStrings); headerListTextBox.Text = headerList; } finally { w.Dispose(); } }, uiScheduler); } Jest to przykäad bardzo dobrego, bezpoĈredniego wykorzystania TPL i zapewnia podobne efekty jak kod z listingu 18.1, choè nie stanowi on dokäadnej reprezentacji sposobu, w jaki kompilator C# przeksztaäca kod. Jak dowiesz siö z dalszej czöĈci rozdziaäu, säowo kluczowe await uĔywa wzorca, który jest obsäugiwany przez klasy Task oraz Task T , lecz który ich nie wymaga. Dodatkowo gwarantuje ono wygenerowanie kodu, który obsäuguje wczeĈniej- sze zakoþczenie (czyli sytuacje, gdy zadanie zostanie wykonane, zanim bödziemy gotowi rozpoczñè oczekiwanie na jego zakoþczenie) znacznie bardziej efektywnie niĔ kod z listingu 18.4. Jednak zanim poznasz wszelkie szczegóäy tego, co robi kompilator, warto siö dowie- dzieè, jakie problemy kompilator za nas rozwiñzuje — a to najlepiej zrobiè, pokazujñc kod, który musielibyĈmy napisaè w C# 4.0. Nasz aktualny przykäad jest caäkiem prosty, gdyĔ realizuje tylko jednñ asynchronicznñ ope- racjö; jednak oprócz dwóch opisanych wczeĈniej czynnoĈci — czyli utworzenia jakiegoĈ wy- woäania zwrotnego obsäugujñcego zakoþczenie oraz zapewnienia, Ĕe zostanie ono wykonane w odpowiednim wñtku — musimy takĔe zadbaè o odpowiedniñ obsäugö instrukcji using za- stosowanej w kodzie z listingu 18.1. Kod z listingu 18.4 nie moĔe uĔywaè instrukcji using, gdyĔ obiekt HttpClient chcemy zwolniè dopiero w momencie, gdy nie bödzie juĔ nam po- trzebny. Wywoäanie metody Dispose tuĔ przed zakoþczeniem metody zewnötrznej nie zda egzaminu, gdyĔ musimy mieè moĔliwoĈè uĔycia obiektu w kodzie kontynuacji, a to zazwy- czaj nastñpi trochö po zakoþczeniu metody. A zatem musimy utworzyè obiekt w jednej me- todzie (zewnötrznej) i zwolniè go w innej (wewnötrznej). A poniewaĔ sami wywoäujemy przy tym metodö Dispose, zatem sami musimy zadbaè o obsäugö wyjñtków. Dlatego teĔ konieczne byäo umieszczenie caäego kodu przeniesionego do metody zwrotnej w bloku try i wywoäanie metody Dispose w bloku finally. (W rzeczywistoĈci zastosowane rozwiñzanie nie jest kom- pletne i niezawodne — gdyby konstruktor klasy HttpRequestMessage lub metoda pobierajñ- ca mechanizm szeregowania zadaþ, co jest raczej maäo prawdopodobne, zgäosiäy wyjñtek, to uĔywany obiekt HttpClient nie zostaäby prawidäowo zwolniony. Innymi säowy, nasz kod obsäuguje jedynie tö sytuacjö, gdy problemy pojawiñ siö w samej operacji sieciowej). Kod z listingu 18.4 uĔywa mechanizmu szeregowania zadaþ, by wykonaè kontynuacjö przy wykorzystaniu obiektu SynchronizationContext, aktywnego w momencie rozpoczynania operacji. Dziöki temu zapewniamy, Ĕe wywoäanie zwrotne zostanie wykonane w wñtku umoĔliwiajñcym aktualizacjö interfejsu uĔytkownika. Choè to w zupeänoĈci wystarcza do za- pewnienia poprawnego dziaäania naszego przykäadu, to jednak säowo kluczowe await robi dla nas nieco wiöcej. Nowe sĥowa kluczowe: async oraz await _ 661 Poleć książkęKup książkę Konteksty wykonania i synchronizacji JeĈli realizacja kodu dociera do wyraĔenia zawierajñcego säowo kluczowe await oraz opera- cjö, której wykonanie nie zakoþczyäo siö od razu, to wygenerowany przez kompilator kod reprezentujñcy await zapewni pobranie aktualnego kontekstu wykonania. (MoĔe siö zdarzyè, Ĕe nie bödzie to wymagaäo wielkiego zachodu — jeĈli nie jest to pierwszy blok await w danej metodzie oraz jeĈli uĔywany kontekst nie zostaä zmieniony, to bödzie on juĔ pobrany). Po za- koþczeniu operacji asynchronicznej dalsza czöĈè kodu metody zostanie wykonana przy wy- korzystaniu kontekstu wykonania2. Zgodnie z informacjami podanymi w rozdziale 17., kontekst wykonania obsäuguje pewne kontekstowe informacje o bezpieczeþstwie oraz lokalny stan wñtku, które muszñ byè przeka- zywane, gdy jedna metoda wywoäuje drugñ (i to nawet jeĈli robi to bezpoĈrednio). Niemniej jednak istnieje jeszcze inny rodzaj kontekstu, który moĔe nas interesowaè, a zwäaszcza jeĈli tworzymy kod obsäugi interfejsu uĔytkownika; chodzi o kontekst synchronizacji. Choè wszystkie wyraĔenia await pobierajñ kontekst wykonania, to decyzja o tym, czy wraz z nim naleĔy pobraè takĔe kontekst synchronizacji, zaleĔy od typu, na który oczekujemy. JeĈli oczekujemy na danñ typu Task, to domyĈlnie kontekst synchronizacji takĔe zostanie pobrany. Zadania nie sñ jedynymi obiektami, na jakie moĔna oczekiwaè, informacje dotyczñce sposobu, w jaki moĔna dostosowaè typy do obsäugi säowa kluczowego await, zostaäy podane w dalszej czöĈci rozdziaäu, w punkcie pt. „Wzorzec säowa kluczowego await”. Czasami mogñ siö zdarzyè sytuacje, w których nie bödziemy chcieli uĔywaè kontekstu syn- chronizacji. JeĈli chcemy wykonaè jakñĈ operacjö asynchronicznñ, rozpoczynajñc jñ w wñtku ob- säugi interfejsu uĔytkownika, a jednoczeĈnie nie ma koniecznoĈci dalszego pozostawania w tym wñtku, to planowanie wykonania wszystkich kontynuacji przy uĔyciu kontekstu synchronizacji bödzie jedynie niepotrzebnym obciñĔeniem. JeĈli operacja asynchroniczna jest reprezentowana przez obiekt Task lub Task T , to uĔywajñc zdefiniowanej w tych klasach metody ConfigureAwait moĔemy zadeklarowaè, Ĕe nie chcemy uĔywaè kontekstu synchronizacji. W takim przypadku zwracana jest nieznacznie zmieniona reprezentacja operacji asynchronicznej, a jeĈli jej uĔyjemy w wyraĔeniu await zamiast oryginalnego zadania, to bieĔñcy kontekst synchronizacji zostanie zignorowany (oczywiĈcie o ile w ogóle bödzie dostöpny). (Nie moĔna natomiast zrezygnowaè z wykorzystania kontekstu wykonania). Listing 18.5 pokazuje, jak moĔna korzystaè z metody ConfigureAwait. Listing 18.5. Stosowanie metody ConfigureAwait private async void OnFetchButtonClick(object sender, RoutedEventArgs e) { using (var w = new HttpClient()) using (Stream f = File.Create(fileTextBox.Text)) { Task Stream getStreamTask = w.GetStreamAsync(urlTextBox.Text); Stream getStream = await getStreamTask.ConfigureAwait(false); Task copyTask = getStream.CopyToAsync(f); await copyTask.ConfigureAwait(false); } } 2 Okazuje siö, Ĕe to samo dzieje siö w przykäadzie z listingu 18.4, gdyĔ TPL pobiera kontekst wykonywania za nas. 662 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę PowyĔszy kod reprezentuje procedurö obsäugi klikniöè przycisku, dlatego teĔ jest wykony- wany w wñtku obsäugi interfejsu uĔytkownika. Pobiera on wartoĈci wäaĈciwoĈci Text kilku pól tekstowych, a nastöpnie wykonuje pewnñ operacjö asynchronicznñ — pobiera zawartoĈè adresu URL i kopiuje pobrane dane do pliku. Po pobraniu zawartoĈci dwóch wäaĈciwoĈci Text powyĔszy kod nie uĔywa juĔ Ĕadnych elementów interfejsu uĔytkownika, a zatem jeĈli wykonanie operacji asynchronicznej trochö zajmuje, to nie bödzie miaäo Ĕadnego znaczenia, Ĕe jej pozostaäa czöĈè zostanie wykonana w innym wñtku. Poprzez przekazanie wartoĈci false w wywoäaniu metody ConfigureAwait oraz poczekanie na zwróconñ przez nie wartoĈè in- formujemy TPL, Ĕe do zakoþczenia operacji moĔe zostaè wykorzystany dowolny wñtek, przy czym w tym przypadku bödzie to najprawdopodobniej jeden z wñtków dostöpnych w puli. Dziöki temu operacja bödzie mogäa zostaè wykonana szybciej i bardziej efektywnie, gdyĔ nie bödzie musiaäa bez potrzeby korzystaè z wñtku obsäugi interfejsu uĔytkownika po kaĔdym säowie kluczowym await. Kod przedstawiony na listingu 18.1 zawiera tylko jedno wyraĔenie ze säowem kluczowym await, lecz nawet ten kod trudno jest odtworzyè, wykorzystujñc klasyczny model progra- mowania z uĔyciem TPL. Przykäad z listingu 18.5 zawiera dwa takie wyraĔenia, a odtworzenie sposobu jego dziaäania bez pomocy await wymagaäoby uĔycia dosyè rozbudowanego kodu, gdyĔ wyjñtki mogäyby byè zgäaszane przed pierwszym wyraĔeniem await, po drugim wyra- Ĕeniu oraz pomiödzy nimi; oprócz tego w kaĔdym z tych przypadków (jak równieĔ w sytuacji, gdy nie zostaäy zgäoszone Ĕadne wyjñtki) musielibyĈmy zadbaè o wywoäanie metody Dispose w celu zwolnienia uĔywanych obiektów HttpClient oraz Stream. Niemniej jednak sytuacja staje siö znaczñco bardziej skomplikowana, kiedy w grö zaczyna dodatkowo wchodziè ste- rowanie przepäywem. Wykonywanie wielu operacji i pýtli ZaäóĔmy, Ĕe zamiast pobieraè nagäówki lub kopiowaè zawartoĈè odpowiedzi HTTP do pliku, chcemy tö zawartoĈè przetworzyè. JeĈli jest ona bardzo duĔa, to pobranie jej jest operacjñ, która moĔe wymagaè wykonania wielu czasochäonnych kroków. Przykäad przedstawiony na listingu 18.6 pobiera caäñ stronö WWW wiersz po wierszu. Listing 18.6. Wykonywanie wielu operacji asynchronicznych private async void FetchAndShowBody(string url) { using (var w = new HttpClient()) { Stream body = await w.GetStreamAsync(url); using (var bodyTextReader = new StreamReader(body)) { while (!bodyTextReader.EndOfStream) { string line = await bodyTextReader.ReadLineAsync(); headerListTextBox.AppendText(line); headerListTextBox.AppendText(Environment.NewLine); await Task.Delay(TimeSpan.FromMilliseconds(10)); } } } } Nowe sĥowa kluczowe: async oraz await _ 663 Poleć książkęKup książkę W powyĔszym kodzie zostaäy uĔyte trzy wyraĔenia await. Pierwsze z nich powoduje wyko- nanie Ĕñdania HTTP GET, a operacja ta zakoþczy siö w momencie odebrania pierwszej czöĈci odpowiedzi, choè w tym momencie odpowiedĒ moĔe jeszcze nie byè kompletna — moĔe za- wieraè jeszcze kilka megabajtów danych, które trzeba bödzie jeszcze przekazaè. PowyĔszy przykäad zakäada, Ĕe zawartoĈè odpowiedzi bödzie tekstowa, dlatego teĔ przekazuje zwróco- ny obiekt Stream jako argument wywoäania konstruktora strumienia StreamReader, który udostöpnia bajty stanowiñce zawartoĈè strumienia jako tekst3. Nastöpnie przykäad uĔywa metody ReadLineAsync, by wiersz po wierszu odczytywaè zawartoĈè odpowiedzi. PoniewaĔ dane sñ przesyäane fragmentami, zatem odczytanie pierwszego wiersza tekstu moĔe trochö zajñè, jednak kilka kolejnych wywoäaþ metody zostanie zapewne wykonanych momentalnie, gdyĔ kaĔdy odebrany pakiet sieciowy zazwyczaj zawiera wiöcej wierszy. JeĈli jednak nasz kod moĔe odczytywaè dane szybciej, niĔ sñ przesyäane sieciñ, to w koþcu odczyta wszystkie wiersze, które byäy dostöpne w pierwszym pakiecie, i pewnie minie trochö czasu, zanim po- jawiñ siö kolejne. Dlatego teĔ wywoäania metody ReadLineAsync bödñ zwracaäy zarówno za- dania, których wykonanie zajmuje wiöcej czasu, jak i takie, które zostanñ zakoþczone bäy- skawicznie. Trzeciñ operacjñ asynchronicznñ jest wywoäanie metody Task.Delay. W powyĔszym przykäadzie zostaäa ona uĔyta po to, by nieco zwolniè odczyt danych i aby kolejne wiersze tekstu pojawiaäy siö w interfejsie uĔytkownika stopniowo. Metoda Task.Delay zwraca obiekt Task, który zostanie zakoþczony po upäywie okreĈlonego czasu; stanowi ona zatem asynchro- niczny odpowiednik metody Thread.Sleep. (Metoda Thread.Sleep blokuje wñtek, w którym zostaäa wywoäana, natomiast wyraĔenie await Task.Delay wprowadza opóĒnienie bez blo- kowania wñtku). W powyĔszym przykäadzie kaĔde z wyraĔeþ await zostaäo umieszczone w odröbnej instrukcji; takie rozwiñzanie nie jest jednak konieczne. Nic nie stoi na przeszkodzie, by uĔyè wyraĔenia o nastöpujñcej postaci: (await t1) + (await t2). (W razie potrzeby moĔna pominñè nawiasy, gdyĔ operator await ma wyĔszy priorytet niĔ operator do- dawania, ja jednak preferujö wizualny porzñdek i hierarchiö, jakñ one zapewniajñ). Nie przedstawiö tu peänego odpowiednika kodu z listingu 18.6, który naleĔaäoby napisaè w jözyku C# 4.0, gdyĔ jest on zbyt duĔy. Ograniczö siö jedynie do przedstawienia kilku pro- blemów. Przede wszystkim w powyĔszym kodzie uĔywamy pötli, wewnñtrz której zostaäy umieszczone dwa wyraĔenia await. Odtworzenie analogicznego kodu z uĔyciem obiektów Task i wywoäaþ zwrotnych oznaczaäoby koniecznoĈè stworzenia wäasnego odpowiednika pötli, gdyĔ jej zawartoĈè musi zostaè rozdzielona na trzy metody: pierwsza z nich rozpoczy- naäaby dziaäanie pötli (byäaby ona metodñ zagnieĔdĔonñ, dziaäajñcñ jako kontynuacja metody GetStreamAsync), a pozostaäe dwie byäyby wywoäaniami zwrotnymi obsäugujñcymi zakoþ- czenie operacji ReadLineAsync oraz Task.Delay. Takie rozwiñzanie moĔna by zaimplemen- towaè, tworzñc metodö zagnieĔdĔonñ säuĔñcñ do rozpoczynania kolejnych iteracji i wywoäujñc jñ z dwóch miejsc: w miejscu, w którym chcemy rozpoczñè dziaäanie pötli, oraz w kontynu- acji zadania Task.Delay w celu rozpoczöcia kolejnej iteracji pötli. Ta technika zostaäa zapre- zentowana na listingu 18.7, choè przedstawia on tylko jeden aspekt dziaäaþ, które wykonuje za nas kompilator — nie jest on kompletnym odpowiednikiem kodu z listingu 18.6. 3 Precyzyjnie rzecz ujmujñc, powinniĈmy sprawdziè nagäówki odpowiedzi HTTP, by okreĈliè uĔyty sposób ko- dowania i w odpowiedni sposób skonfigurowaè obiekt StreamReader. Jednak w tym przykäadzie pozwalamy, by obiekt strumienia sam okreĈliä sposób kodowania, co na potrzeby przykäadu powinno dziaäaè wystarcza- jñco dobrze. 664 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę Listing 18.7. Niekompletna samodzielna implementacja pötli asynchronicznej private void IncompleteOldSchoolFetchAndShowBody(string url) { var w = new HttpClient(); var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext(); w.GetStreamAsync(url).ContinueWith(getStreamTask = { Stream body = getStreamTask.Result; var bodyTextReader = new StreamReader(body); Action startNextIteration = null; startNextIteration = () = { if (!bodyTextReader.EndOfStream) { bodyTextReader.ReadLineAsync() .ContinueWith(readLineTask = { string line = readLineTask.Result; headerListTextBox.AppendText(line); headerListTextBox.AppendText(Environment.NewLine); Task.Delay(TimeSpan.FromMilliseconds(10)) .ContinueWith(delayTask = startNextIteration(), uiScheduler); }, uiScheduler); } }; startNextIteration(); }, uiScheduler); } Ten kod dziaäa jako tako, jednak nawet nie podejmuje próby zwolnienia któregokolwiek z uĔywanych zasobów. Wystöpuje w nim kilka miejsc, w których potencjalnie moĔe dojĈè do awarii, dlatego nie wystarczy umieĈè w kodzie jednej instrukcji using lub pary bloków try/finally, aby zabezpieczyè dziaäanie kodu. A nawet bez tego dodatkowego utrudnienia dziaäanie kodu ledwie moĔna zrozumieè — wcale nie jest oczywiste, Ĕe próbuje on wykonaè te same operacje co przykäad z listingu 18.6. Po dodaniu odpowiedniej obsäugi bäödów ten kod byäby caäkowicie niezrozumiaäy. W praktyce zapewne äatwiej by byäo zastosowaè caäko- wicie inne rozwiñzanie, polegajñce na napisaniu klasy implementujñcej maszynö stanów i na tej podstawie okreĈlajñcej czynnoĈci, jakie ma wykonywaè. Takie rozwiñzanie zapewne uäatwi- äoby napisanie prawidäowo dziaäajñcego kodu, jednak wcale nie uäatwiäoby osobie analizujñ- cej kod zorientowaè siö, Ĕe to, na co patrzy, jest w rzeczywistoĈci niewiele wiöcej niĔ pötlñ. Nic zatem dziwnego, Ĕe tak wielu programistów preferuje stosowanie rozwiñzaþ synchro- nicznych. Jednak C# 5.0 pozwala nam pisaè kod asynchroniczny, który ma niemal takñ samñ strukturö co jego synchroniczny odpowiednik, bezboleĈnie zapewniajñc nam przy tym wszyst- kie korzyĈci zwiñzane z wiökszñ wydajnoĈciñ dziaäania i sprawnym reagowaniem na poczy- nania uĔytkownika. NajproĈciej rzecz ujmujñc, wäaĈnie te korzyĈci zapewniajñ nam säowa kluczowe async oraz await. KaĔda metoda wykorzystujñca säowo kluczowe await sama bödzie wykonywana przez jakiĈ okreĈlony czas. A zatem oprócz korzystania z asynchronicznych API moĔemy uznaè za sto- sowne, by stworzyè dla niej jakñĈ asynchronicznñ reprezentacjö. Oba przedstawione säowa kluczowe pomagajñ nam to zrobiè. Nowe sĥowa kluczowe: async oraz await _ 665 Poleć książkęKup książkę Zwracanie obiektu Task Kompilator C# narzuca pewne ograniczenia na typy wartoĈci wynikowych, które mogñ zwra- caè metody oznaczone modyfikatorem async. Jak juĔ siö dowiedzieliĈmy, mogñ one zwracaè void, jednak oprócz tego istniejñ dwie inne moĔliwoĈci: moĔna zwracaè instancjö typu Task bñdĒ typu Task T , gdzie T jest dowolnym typem. Dziöki temu kod wywoäujñcy naszñ asyn- chronicznñ metodö moĔe uzyskiwaè informacje o statusie wykonywanych przez niñ prac, a oprócz tego dysponuje moĔliwoĈciñ doäñczania do niej kontynuacji, a takĔe pobierania wy- niku (jeĈli zwracany jest obiekt Task T ). Oznacza to oczywiĈcie, Ĕe jeĈli nasza metoda jest wywoäywana wewnñtrz innej metody asynchronicznej (oznaczonej modyfikatorem async), to jej wynik bödzie moĔna pobraè, uĔywajñc säowa kluczowego await. Zwracanie zadaþ jest zazwyczaj bardziej preferowanym rozwiñzaniem niĔ zwracanie typu void, gdyĔ w tym drugim przypadku kod wywoäujñcy nie dysponuje tak naprawdö moĔli- woĈciñ okreĈlenia, kiedy metoda zostaäa zakoþczona oraz czy naleĔy zgäosiè wyjñtek. (Metody asynchroniczne mogñ dziaäaè nawet po przekazaniu sterowania do kodu wywoäujñcego — w koþcu wäaĈnie o to w nich chodzi — a zatem w momencie, kiedy nasza metoda zgäosi wy- jñtek, metody, która jñ wywoäaäa, moĔe juĔ w ogóle nie byè na stosie). Zwracajñc obiekt Task lub Task T , zapewniamy kompilatorowi moĔliwoĈè udostöpniania wyjñtków oraz w razie potrzeby zwracania wyników. Oprócz ograniczenia nakazujñcego stosowanie modyfikatora async wyäñcznie w me- todach zwracajñcych wynik typu void, Task bñdĒ Task T nie moĔna go takĔe uĔy- waè w metodzie stanowiñcej punkt wejĈcia do programu, czyli w metodzie Main. Zwrócenie zadania jest tak trywialnie proste, Ĕe nie ma Ĕadnego powodu, by tego nie robiè. Aby zmodyfikowaè metodö z listingu 18.6 tak, by zwracaäa zadanie, trzeba wprowadziè tylko jednñ zmianö. Wystarczy zmieniè typ wartoĈci wynikowej z void na Task, jak pokazuje li- sting 18.8 — reszta kodu moĔe pozostaè bez zmian. Listing 18.8. Zwracanie zadania private async Task FetchAndShowBody(string url) ... jak wczeŁniej Kompilator automatycznie generuje kod wymagany do utworzenia obiektu Task i w zaleĔnoĈci od tego, czy metoda zwróci wynik, czy zgäosi wyjñtek, ustawia jego status na zakoþczony lub zakoþczony niepowodzeniem. TakĔe zwracanie wyniku z zadania jest bardzo äatwe. Wystarczy uĔyè typu Task T , a w kodzie metody umieĈciè instrukcjö return, jak gdyby zwracaäa ona wartoĈè typu T. Przykäad takiej metody zostaä przedstawiony na listingu 18.9. Listing 18.9. Zwracanie zadania Task T public static async Task string GetServerHeader(string url) { using (var w = new HttpClient()) { var request = new HttpRequestMessage(HttpMethod.Head, url); HttpResponseMessage response = await w.SendAsync(request, HttpCompletionOption.ResponseHeadersRead); string result = null; IEnumerable string values; 666 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę if (response.Headers.TryGetValues( Server , out values)) { result = values.FirstOrDefault(); } return result; } } PowyĔsza metoda asynchronicznie pobiera nagäówki HTTP, tak samo jak przykäad z listingu 18.1, jednak zamiast je wyĈwietlaè, pobiera i zwraca wartoĈè pierwszego nagäówka Server:. Jak widaè, instrukcja return zwraca äaþcuch znaków, choè zadeklarowanym typem wartoĈci wynikowej metody jest Task string . Kompilator generuje kod, który koþczy wykonywanie zadania i uĔywa zwróconego äaþcucha znaków jako wyniku. W przypadku uĔycia typu Task lub Task T wygenerowany kod zwraca zadanie bardzo podobne do tego, które moĔna uzy- skaè, uĔywajñc klasy TaskCompletionSource T , opisanej w rozdziale 17. Choè säowo kluczowe await moĔe operowaè na dowolnej metodzie asynchronicznej pasujñcej do okreĈlonego wzorca (opisanego w dalszej czöĈci rozdziaäu), to jednak C# nie zapewnia równie wielkiej elastycznoĈci, jeĈli chodzi o moĔliwoĈci implementacji metod asynchronicznych. Jedynymi typami, jakie mogñ zwracaè metody z modyfi- katorem async sñ: Task, Task T oraz void. Jednak zwracanie zadaþ ma pewnñ wadö. OtóĔ kod wywoäujñcy nie ma obowiñzku robiè cze- gokolwiek z tak zwróconym zadaniem, zatem nasza metoda moĔe byè równie äatwa w uĔy- ciu co metoda zwracajñca typ void, a jednoczeĈnie ma tö zaletö, Ĕe udostöpnia zadanie, które kod wywoäujñcy moĔe wykorzystaè. Chyba jedynym powodem zwracania typu void mogäoby byè narzucenie przez kod zewnötrzny koniecznoĈci uĔycia metody o okreĈlonej sygnaturze. Na przykäad wiökszoĈè procedur obsäugi zdarzeþ musi uĔywaè typu void. Jednak oprócz sytuacji, gdy jesteĈmy do tego zmuszeni, stosowanie w metodach asynchronicznych typu void nie jest zalecane. Stosowanie async w metodach zagnieŜdŜonych W przykäadach przedstawionych do tej pory uĔywaliĈmy säowa kluczowego async tylko w zwyczajnych metodach. Jednak moĔna je takĔe stosowaè w metodach zagnieĔdĔonych — zarówno metodach anonimowych, jak i w wyraĔeniach lambda. Na przykäad: jeĈli piszemy program, który tworzy elementy interfejsu uĔytkownika programowo, wygodnym rozwiñza- niem moĔe byè doäñczanie procedur obsäugi zdarzeþ w formie wyraĔeþ lambda, moĔemy siö przy tym zdecydowaè, by niektóre z nich zostaäy zaimplementowane jako asynchroniczne, jak pokazano na listingu 18.10. Listing 18.10. Asynchroniczne wyraĔenie lambda okButton.Click += async (s, e) = { using (var w = new HttpClient()) { infoTextBlock.Text = await w.GetStringAsync(uriTextBox.Text); } }; Skäadnia asynchronicznej metody anonimowej jest bardzo podobna, jak widaè w przykäadzie przedstawionym na listingu 18.11. Nowe sĥowa kluczowe: async oraz await _ 667 Poleć książkęKup książkę Listing 18.11. Asynchroniczna metoda anonimowa okButton.Click += async delegate (object s, RoutedEventArgs e) { using (var w = new HttpClient()) { infoTextBlock.Text = await w.GetStringAsync(uriTextBox.Text); } }; ēeby wszystko byäo jasne — powyĔszy kod nie ma nic wspólnego z asynchronicznym wy- woäywaniem delegatów, czyli technikñ, o której wspominaäem w rozdziale 9., säuĔñcñ do ko- rzystania z puli wñtków i popularnñ, zanim metody anonimowe i TPL staäy siö lepszñ alter- natywñ. Asynchroniczne wywoäywanie delegatów jest rozwiñzaniem, na które moĔe siö zdecydowaè kod korzystajñcy z delegatu — jednak w takim przypadku asynchronicznoĈè nie jest ani cechñ delegatu, ani metody, która go wywoäuje. Jest to jedynie rozwiñzanie zastoso- wane przez kod uĔywajñcy delegatu. Jednak zastosowanie modyfikatora async w metodzie anonimowej lub wyraĔeniu lambda pozwala nam na korzystanie wewnñtrz nich ze säowa kluczowego await, zmieniajñc w ten sposób kod metody generowany przez kompilator. Wzorzec sĥowa kluczowego await WiökszoĈè metod asynchronicznych, których bödziemy uĔywaè wraz ze säowem kluczowym await, zwraca jakieĈ zadania TPL. Niemniej jednak C# wcale tego nie wymaga. Kompilator po- zwala na stosowanie ze säowem kluczowym await dowolnych obiektów, implementujñcych okreĈlony wzorzec. Choè klasy Task i Task T , obsäugujñ ten wzorzec, to jednak sposób jego dziaäania oznacza, Ĕe kompilator bödzie uĔywaä zadaþ w nieco inny sposób, niĔ to robimy, ko- rzystajñc z biblioteki TPL bezpoĈrednio — po czöĈci wäaĈnie z tego powodu napisaäem wcze- Ĉniej, Ĕe kod wykorzystujñcy zadania i stanowiñcy odpowiednik kodu uĔywajñcego säowa kluczowego await nie stanowi dokäadnego odpowiednika kodu generowanego przez kom- pilator. W tym podrozdziale wyjaĈniö, jak kompilator uĔywa zadaþ oraz innych typów, które mogñ byè stosowane wraz ze säowem kluczowym await. W dalszej czöĈci tego podrozdziaäu stworzymy wäasnñ implementacjö wzorca säowa kluczo- wego await, aby pokazaè, czego oczekuje kompilator. (Tak siö skäada, Ĕe Visual Basic rozpo- znaje i obsäuguje dokäadnie ten sam wzorzec). Listing 18.12 przedstawia metodö asynchro- nicznñ o nazwie UseCustomAsync, która korzysta z naszej asynchronicznej implementacji. Metod ta zapisuje wynik wyraĔenia await w zmiennej typu string, a zatem najwyraĒniej oczekuje, Ĕe nasza asynchroniczna operacja zwróci äaþcuch znaków. Wywoäuje ona metodö CustomAsync, zwracajñcñ tö implementacjö wzorca. Jak widaè, nie jest to wcale Task string . Listing 18.12. Wywoäywanie niestandardowej implementacji typu wspóäpracujñcego z await static async Task UseCustomAsync() { string result = await CustomAsync(); Console.WriteLine(result); } public static MyAwaitableType CustomAsync() { return new MyAwaitableType(); } 668 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę Kompilator oczekuje, Ĕe typ operandu säowa kluczowego await bödzie udostöpniaä metodö o nazwie GetAwaiter. MoĔe to byè zwyczajna metoda skäadowa bñdĒ metoda rozszerzenia. (A zatem definiujñc odpowiedniñ metodö rozszerzenia, moĔna sprawiè, Ĕe säowo kluczowe await bödzie wspóäpracowaäo z typem, który sam z siebie go nie obsäuguje). Metoda ta musi zwracaè obiekt lub wartoĈè zapewniajñcñ trzy moĔliwoĈci. Przede wszystkim musi udostöpniaè wäaĈciwoĈè typu bool o nazwie IsCompleted, którñ kod wygenerowany przez kompilator do obsäugi säowa kluczowego await bödzie sprawdzaä w celu okreĈlenia, czy operacja juĔ siö zakoþczyäa. W przypadku gdy operacja zostaäa juĔ za- koþczona, przygotowywanie wywoäania zwrotnego byäoby stratñ czasu. A zatem kod obsäu- gujñcy säowo kluczowe await nie bödzie tworzyè niepotrzebnego delegatu, jeĈli wäaĈciwoĈè IsCompleted zwróci wartoĈè true, a zamiast tego od razu wykona dalszñ czöĈè metody. Oprócz tego kompilator wymaga jakiegoĈ sposobu pobrania wyniku, kiedy operacja zostanie juĔ zakoþczona. Dlatego teĔ obiekt lub wartoĈè zwracana przez metodö GetAwaiter musi udo- stöpniaè metodö GetResult. Typ wyniku zwracanego przez tö metodö definiuje typ wyniku operacji — a zatem bödzie to typ caäego wyraĔenia await. W przykäadzie z listingu 18.12 wynik wyraĔenia await jest zapisywany w zmiennej typu string, a zatem wynik zwracany przez metodö GetResult obiektu zwróconego przez metodö GetAwaiter klasy MyAwaitableType musi byè typu string (bñdĒ jakiegoĈ innego typu, który niejawnie moĔna skonwertowaè na string). I w koþcu ostatniñ moĔliwoĈciñ, której potrzebuje kompilator, jest dostarczenie metody zwrotnej. JeĈli wäaĈciwoĈè IsCompleted zwróci wartoĈè false, informujñc tym samym, Ĕe operacja jesz- cze siö nie zakoþczyäa, to kod wygenerowany przez kompilator do obsäugi säowa kluczowego await wygeneruje delegat, który wykona pozostaäñ czöĈè kodu metody. (Przypomina to nieco przekazywanie delegatu do metody ContinueWith zadania). Kompilator wymaga w tym celu nie metody, lecz caäego interfejsu. Musimy zatem zaimplementowaè interfejs INotifyCompletion, lecz oprócz niego istnieje jeszcze jeden interfejs, ICiriticalNotifyCompletion, którego im- plementacja jest zalecana, o ile tylko jest to moĔliwe. Oba te interfejsy sñ podobne: kaĔdy z nich definiuje jednñ metodö (OnCompleted oraz UnsafeOnCompleted), która pobiera jeden delegat typu Action, który klasa implementujñca interfejs musi wywoäaè w momencie zakoþczenia operacji. Oba te interfejsy oraz ich metody róĔniñ siö tym, Ĕe pierwszy z nich wymaga od klasy implementujñcej przekazania kontekstu wykonania do metody docelowej, natomiast w przy- padku drugiego interfejsu nie jest to konieczne. Kompilator C# zawsze przekazuje kontekst wykonania za nas, a zatem jeĈli metoda UnsafeOnCompleted bödzie dostöpna, to kompilator wywoäa jñ, by uniknñè dwukrotnego przekazywania kontekstu. (JeĈli kompilator wywoäa metodö OnCompleted, to takĔe obiekt zwrócony przez metodö GetAwaiter przekaĔe kontekst wykonania). Niemniej jednak skorzystanie z metody UnsafeOnCompleted moĔe byè niemoĔ- liwe ze wzglödów bezpieczeþstwa. PoniewaĔ metoda ta nie przekazuje kontekstu wykona- nia, zatem kod niedysponujñcy peänym zaufaniem nie moĔe jej wywoäywaè, gdyĔ pozwala- äoby to na ominiöcie pewnych mechanizmów zabezpieczeþ. Metoda UnsafeOnCompleted jest oznaczona atrybutem SecurityCriticalAttribute, co oznacza, Ĕe moĔe jñ wywoäywaè tylko kod dysponujñcy peänym zaufaniem. A zatem metoda OnCompleted jest potrzebna, by takĔe kod, który nie dysponuje peänym zaufaniem, mógä korzystaè z obiektu zwracanego przez metodö GetAwaiter. Listing 18.13 przedstawia minimalnñ, nadajñcñ siö do uĔycia implementacjö wzorca säowa kluczowego await. Przedstawiony kod jest jednak bardzo uproszczony, gdyĔ zawsze koþczy siö synchronicznie, a zatem jego metoda OnCompleted nic nie robi. W rzeczywistoĈci, jeĈli na- sza przykäadowa klasa zostanie uĔyta w taki sposób, w jaki wzorzec await ma byè uĔywany, Wzorzec sĥowa kluczowego await _ 669 Poleć książkęKup książkę to jej metoda OnCompleted w ogóle nie zostanie wywoäana — wäaĈnie dlatego zgäasza wyjñtek. Niemniej jednak choè przedstawiony przykäad jest nierealistycznie prosty, to jednak caäkiem dobrze pokazuje sposób dziaäania säowa kluczowego await. Listing 18.13. Wyjñtkowo prosta implementacja wzorca säowa kluczowego await public class MyAwaitableType { public MinimalAwaiter GetAwaiter() { return new MinimalAwaiter(); } public class MinimalAwaiter : INotifyCompletion { public bool IsCompleted { get { return true; } } public string GetResult() { return Oto wynik! ; } public void OnCompleted(Action continuation) { throw new NotImplementedException(); } } } Po przedstawieniu tego kodu moĔemy juĔ zobaczyè, jak dziaäa przykäad z listingu 18.12. Wywoäa on metodö GetAwaiter instancji typu MyAwaitableType zwróconej przez metodö CustomAsync. Nastöpnie sprawdzi wartoĈè wäaĈciwoĈci IsCompleted uzyskanego obiektu i jeĈli okaĔe siö, Ĕe ma ona wartoĈè true (co teĔ siö stanie), to bezzwäocznie zostanie wykonana reszta metody. Kompilator nie wie o tym, Ĕe wäaĈciwoĈè IsCompleted zawsze ma wartoĈè true, dlatego teĔ wygeneruje kod pozwalajñcy na prawidäowe obsäuĔenie przypadku, gdyby wäaĈciwoĈè ta przyjöäa wartoĈè false. Kod ten utworzy delegat, który kiedy zostanie wywoäany, wykona po- zostaäñ czöĈè metody, po czym przekaĔe ten delegat do metody OnComplete. (Nasz przykäadowy kod nie implementuje metody UnsafeOnCompleted, zatem zostanie uĔyta metoda OnCompleted). Kod, który wykonuje te wszystkie operacje, zostaä przedstawiony na listingu 18.14. Listing 18.14. Bardzo ogólne przybliĔenie dziaäania säowa kluczowego await static void ManualUseCustomAsync() { var awaiter = CustomAsync().GetAwaiter(); if (awaiter.IsCompleted) { TheRest(awaiter); } else { awaiter.OnCompleted(() = TheRest(awaiter)); } } private static void TheRest(MyAwaitableType.MinimalAwaiter awaiter) { string result = awaiter.GetResult(); Console.WriteLine(result); } 670 _ Rozdziaĥ 18. Asynchroniczne cechy jýzyka Poleć książkęKup książkę Metoda zostaäa podzielona na dwie czöĈci, gdyĔ kompilator unika tworzenia delegatu, jeĈli wäaĈciwoĈè IsCompleted przyjmie wartoĈè true, a my chcemy, by nasz kod dziaäaä podob- nie. Niemniej jednak nie jest to dokäadnie to samo, co robi kompilator C# — potrafi on takĔe uniknñè tworzenia dodatkowych metod dla poszczególnych instrukcji await, choè oznacza to, Ĕe generowany przez niego kod jest znaczñco bardziej skomplikowany. W rzeczywistoĈci w przypadku metod zawierajñcych tylko jedno säowo kluczowe await generowany przez kompilator narzut jest znaczñco wiökszy do tego z listingu 18.14. Niemniej jednak wraz ze wzrostem liczby uĔywanych wyraĔeþ await ta dodatkowa zäoĔonoĈè zaczyna siö opäacaè, gdyĔ kompilator nie musi dodawaè kolejnych metod. Listing 18.15 przedstawia kod, który w nieco wiökszym stopniu przypomina to, co faktycznie generuje kompilator. Listing 18.15. Nieco lepsze przybliĔenie sposobu dziaäania säowa kluczowego await private class ManualUseCustomAsyncState { private int state; private MyAwaitableType.MinimalAwaiter awaiter; public void MoveNext() { if (state == 0) { awaiter = CustomAsync().GetAwaiter(); if (!awaiter.IsCompleted) { state = 1; awaiter.OnCompleted(MoveNext); return; } } string result = awaiter.GetResult(); Console.WriteLine(result); } } static void ManualUseCustomAsync() { var s = new ManualUseCustomAsyncState(); s.MoveNext(); } PowyĔszy kod i tak jest prostszy do tego, który kompilator gen
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

C# 5.0. Programowanie. Tworzenie aplikacji Windows 8, internetowych oraz biurowych w .NET 4.5 Framework
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: