Tytuł oryginału: C# 6.0 in a Nutshell, 6th...
Transcript of Tytuł oryginału: C# 6.0 in a Nutshell, 6th...
Tytuł oryginału: C# 6.0 in a Nutshell, 6th Edition
Tłumaczenie: Łukasz Piwko (wstęp, rozdz. 1 – 11, 20 – 24) Robert Górczyński (12 – 18, 26 – 27) Jakub Hubisz (rozdz. 19, 25)
ISBN: 978-83-283-2423-7
© 2016 Helion SA
Authorized Polish translation of the English edition C# 6.0 in a Nutshell, 6th Edition ISBN 9781491927069 © 2016 Joseph Albahari, Ben Albahari.
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.
Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłez wykorzystania informacji zawartych w książce.
Wydawnictwo HELIONul. Kościuszki 1c, 44-100 GLIWICEtel. 32 231 22 19, 32 230 98 63e-mail: [email protected]: 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/c6pig6Moż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/c6pig6.zip
Printed in Poland.
• Kup książkę• Poleć książkę • Oceń książkę
• Księgarnia internetowa• Lubię to! » Nasza społeczność
3
Spis treści
Wstęp ............................................................................................................................. 11
1 Wprowadzenie do C# i .NET Framework ............................................................................ 17Obiektowość 17Bezpieczeństwo typów 18Zarządzanie pamięcią 19Platformy 19Powiązania C# z CLR 19CLR i .NET Framework 20C# i środowisko wykonawcze systemu Windows 21Co nowego w C# 6.0 22Co było nowego w C# 5.0 24Co było nowego w C# 4.0 24Co było nowego w C# 3.0 25
2 Podstawy języka C# ......................................................................................................... 27Pierwszy program w języku C# 27Składnia 30Podstawy typów 33Typy liczbowe 42Typ logiczny i operatory 49Łańcuchy znaków i pojedyncze znaki 51Tablice 53Zmienne i parametry 57Wyrażenia i operatory 65Operatory null 70Instrukcje 71Przestrzenie nazw 79
Poleć książkęKup książkę
4 Spis treści
3 Tworzenie typów w języku C# ...........................................................................................87Klasy 87Dziedziczenie 101Typ object 109Struktury 113Modyfikatory dostępu 114Interfejsy 116Wyliczenia 121Typy zagnieżdżone 124Typy generyczne 125
4 Zaawansowane elementy języka C# ...............................................................................139Delegaty 139Zdarzenia 147Wyrażenia lambda 153Metody anonimowe 157Instrukcje try i wyjątki 158Wyliczanie i iteratory 166Typy wartościowe dopuszczające wartość null 171Przeciążanie operatorów 177Metody rozszerzające 180Typy anonimowe 182Wiązanie dynamiczne 183Atrybuty 191Atrybuty informacji wywołującego 193Niebezpieczny kod i wskaźniki 194Dyrektywy preprocesora 198Dokumentacja XML 200
5 Ogólny zarys platformy ..................................................................................................205CLR i rdzeń platformy 207Technologie praktyczne 212
6 Podstawowe wiadomości o platformie ...........................................................................219Obsługa łańcuchów i tekstu 219Data i godzina 232Daty i strefy czasowe 239Formatowanie i parsowanie 244Standardowe łańcuchy formatu i flagi parsowania 250Inne mechanizmy konwersji 257Globalizacja 261Praca z liczbami 262
Poleć książkęKup książkę
Spis treści 5
Wyliczenia 266Krotki 269Struktura Guid 271Sprawdzanie równości 271Określanie kolejności 281Klasy pomocnicze 284
7 Kolekcje ........................................................................................................................ 289Przeliczalność 289Interfejsy ICollection i IList 296Klasa Array 300Listy, kolejki, stosy i zbiory 308Słowniki 316Kolekcje i pośredniki z możliwością dostosowywania 322Dołączanie protokołów równości i porządkowania 328
8 Zapytania LINQ .............................................................................................................. 335Podstawy 335Składnia płynna 337Wyrażenia zapytań 343Wykonywanie opóźnione 347Podzapytania 353Tworzenie zapytań złożonych 356Strategie projekcji 360Zapytania interpretowane 362LINQ to SQL i Entity Framework 368Budowanie wyrażeń zapytań 381
9 Operatory LINQ .............................................................................................................. 387Informacje ogólne 388Filtrowanie 391Projekcja 395Łączenie 406Porządkowanie 413Grupowanie 416Operatory zbiorów 419Metody konwersji 420Operatory elementów 423Metody agregacyjne 425Kwantyfikatory 429Metody generujące 430
Poleć książkęKup książkę
6 Spis treści
10 LINQ to XML ...................................................................................................................433Przegląd architektury 433Informacje ogólne o X-DOM 434Tworzenie drzewa X-DOM 437Nawigowanie i wysyłanie zapytań 440Modyfikowanie drzewa X-DOM 444Praca z wartościami 447Dokumenty i deklaracje 450Nazwy i przestrzenie nazw 453Adnotacje 458Projekcja do X-DOM 459
11 Inne technologie XML ....................................................................................................465Klasa XmlReader 466Klasa XmlWriter 474Typowe zastosowania klas XmlReader i XmlWriter 476XSD i sprawdzanie poprawności schematów 480XSLT 483
12 Zwalnianie zasobów i mechanizm usuwania nieużytków ................................................485IDisposable, Dispose i Close 485Automatyczne usuwanie nieużytków 491Finalizatory 493Jak działa mechanizm usuwania nieużytków? 498Wycieki pamięci zarządzanej 503Słabe odwołania 507
13 Diagnostyka i kontrakty kodu .........................................................................................511Kompilacja warunkowa 511Debugowanie i klasy monitorowania 515Ogólne omówienie kontraktów kodu 518Warunki początkowe 523Warunki końcowe 527Asercje i metody inwariantów obiektu 529Kontrakty w interfejsach i metodach abstrakcyjnych 531Rozwiązywanie problemów z awariami podczas użycia kontraktów 532Selektywne egzekwowanie kontraktów 534Statyczne sprawdzenie kontraktu 536Integracja z debuggerem 538Procesy i wątki procesów 539Klasy StackTrace i StackFrame 540Dziennik zdarzeń Windows 542
Poleć książkęKup książkę
Spis treści 7
Liczniki wydajności 544Klasa Stopwatch 549
14 Współbieżność i asynchroniczność .................................................................................. 551Wprowadzenie 551Wątkowanie 552Zadania 569Reguły asynchroniczności 577Funkcje asynchroniczne w języku C# 582Wzorce asynchroniczności 598Wzorce uznane za przestarzałe 606
15 Strumienie i wejście-wyjście .......................................................................................... 611Architektura strumienia 611Użycie strumieni 613Adapter strumienia 626Kompresja strumienia 634Praca z plikami w postaci archiwum ZIP 636Operacje na plikach i katalogach 637Plikowe operacje wejścia-wyjścia w środowisku uruchomieniowym Windows 648Mapowanie plików w pamięci 650Odizolowany magazyn danych 653
16 Sieć ............................................................................................................................... 661Architektura sieci 661Adresy i porty 664Adresy URI 665Klasy po stronie klienta 667Praca z HTTP 680Utworzenie serwera HTTP 685Użycie FTP 688Użycie DNS 690Wysyłanie poczty elektronicznej za pomocą SmtpClient 691Użycie TCP 692Otrzymywanie poczty elektronicznej POP3 za pomocą TCP 695TCP w środowisku uruchomieniowym Windows 697
17 Serializacja .................................................................................................................... 699Koncepcje serializacji 699Serializacja kontraktu danych 703Kontrakty danych i kolekcje 713Rozszerzenie kontraktu danych 715
Poleć książkęKup książkę
8 Spis treści
Serializacja binarna 718Atrybuty serializacji binarnej 720Serializacja binarna za pomocą ISerializable 724Serializacja XML 727
18 Podzespoły ....................................................................................................................737Co znajduje się w podzespole? 737Silne nazwy i podpisywanie podzespołu 742Nazwy podzespołów 745Technologia Authenticode 748Global Assembly Cache 751Zasoby i podzespoły satelickie 754Wyszukiwanie i wczytywanie podzespołów 762Wdrażanie podzespołów poza katalogiem bazowym 768Umieszczenie w pojedynczym pliku wykonywalnym 769Praca z podzespołami, do których nie ma odwołań 771
19 Refleksje i metadane .....................................................................................................773Refleksje i aktywacja typów 774Refleksje i wywoływanie składowych 780Refleksje dla podzespołów 792Praca z atrybutami 793Generowanie dynamicznego kodu 799Emitowanie podzespołów i typów 805Emitowanie składowych typów 809Emitowanie generycznych typów i klas 814Kłopotliwe cele emisji 816Parsowanie IL 819
20 Programowanie dynamiczne ..........................................................................................825Dynamiczny system wykonawczy języka 825Unifikacja typów liczbowych 827Dynamiczne wybieranie przeciążonych składowych 828Implementowanie obiektów dynamicznych 833Współpraca z językami dynamicznymi 836
21 Bezpieczeństwo .............................................................................................................839Uprawnienia 839Zabezpieczenia dostępu kodu 843Dopuszczanie częściowo zaufanych wywołujących 846Model transparentności 848
Poleć książkęKup książkę
Spis treści 9
Ograniczanie innego zestawu 856Zabezpieczenia systemu operacyjnego 860Tożsamości i role 862Kryptografia 864Windows Data Protection 864Obliczanie skrótów 865Szyfrowanie symetryczne 867Szyfrowanie kluczem publicznym i podpisywanie 871
22 Zaawansowane techniki wielowątkowości ..................................................................... 877Przegląd technik synchronizacji 878Blokowanie wykluczające 878Blokady i bezpieczeństwo ze względu na wątki 886Blokowanie bez wykluczania 892Sygnalizacja przy użyciu uchwytów zdarzeń oczekiwania 897Klasa Barrier 905Leniwa inicjalizacja 906Pamięć lokalna wątku 909Metody Interrupt i Abort 911Metody Suspend i Resume 912Zegary 913
23 Programowanie równoległe .......................................................................................... 917Dlaczego PFX? 917PLINQ 920Klasa Parallel 933Równoległe wykonywanie zadań 939Klasa AggregateException 948Kolekcje współbieżne 951Klasa BlockingCollection<T> 954
24 Domeny aplikacji ........................................................................................................... 959Architektura domeny aplikacji 959Tworzenie i likwidowanie domen aplikacji 961Posługiwanie się wieloma domenami aplikacji 962Metoda DoCallBack 964Monitorowanie domen aplikacji 965Domeny i wątki 965Dzielenie danych między domenami 967
Poleć książkęKup książkę
10 Spis treści
25 Współpraca ....................................................................................................................973Odwołania do natywnych bibliotek DLL 973Szeregowanie 974Wywołania zwrotne z kodu niezarządzanego 977Symulowanie unii C 977Pamięć współdzielona 978Mapowanie struktury na pamięć niezarządzaną 981Współpraca COM 985Wywołanie komponentu COM z C# 986Osadzanie typów współpracujących 990Główne moduły współpracujące 990Udostępnianie obiektów C# dla COM 991
26 Wyrażenia regularne .....................................................................................................993Podstawy wyrażeń regularnych 994Kwantyfikatory 998Asercje o zerowej wielkości 999Grupy 1002Zastępowanie i dzielenie tekstu 1003Receptury wyrażeń regularnych 1005Leksykon języka wyrażeń regularnych 1008
27 Kompilator Roslyn ....................................................................................................... 1013Architektura Roslyn 1014Drzewa składni 1015Kompilacja i model semantyczny 1030
Skorowidz ................................................................................................................... 1041
Poleć książkęKup książkę
289
7Kolekcje
Platforma .NET Framework zapewnia standardowy zestaw typów do sortowania i obsługiwaniakolekcji obiektów. Wśród nich można znaleźć listy o zmiennym rozmiarze, listy powiązane, sortowanei niesortowane słowniki oraz tablice. Z tych wszystkich typów jedynie tablice należą do języka C#.Pozostałe kolekcje są tylko klasami, których obiekty można tworzyć tak samo jak obiekty wszystkichinnych klas.
Typy kolekcji platformy można podzielić na następujące kategorie:
interfejsy definiujące standardowe protokoły kolekcji;
gotowe do użycia klasy kolekcji (listy, słowniki itd.);
klasy bazowe do pisania kolekcji specjalnie dostosowanych do potrzeb konkretnych aplikacji.
W tym rozdziale opisujemy wszystkie te kategorie oraz dodatkowo poświęcamy nieco miejsca typomwykorzystywanym do porównywania i porządkowania elementów.
Oto wykaz przestrzeni nazw, w których znajdują się różne kolekcje.
Przestrzeń nazw Zawartość
System.Collections Niegeneryczne klasy i interfejsy kolekcji
System.Collections.Specialized Silnie typizowane niegeneryczne klasy kolekcji
System.Collections.Generic Generyczne klasy i interfejsy kolekcji
System.Collections.ObjectModel Klasy pośrednie i bazowe do tworzenia niestandardowych kolekcji
System.Collections.Concurrent Kolekcje bezpieczne wątkowo (zob. rozdział 23.)
PrzeliczalnośćIstnieje wiele różnych rodzajów kolekcji, od prostych struktur danych, przez tablice i listy powiązanepo złożone struktury, takie jak drzewa czerwono-czarne i tablice skrótów. Choć konstrukcje teznacznie różnią się pod względem budowy zarówno wewnętrznych, jak i zewnętrznych cech, prawiewszystkie z nich można przeglądać. Platforma .NET zapewnia tę możliwość przez dwa interfejsy
Poleć książkęKup książkę
290 Rozdział 7. Kolekcje
(IEnumerable i IEnumerator oraz ich generyczne odpowiedniki), dzięki którym różne struktury danychudostępniają jednakowy interfejs API do przeglądania ich zawartości. Wymienione interfejsy należądo szerszego zbioru przedstawionego na rysunku 7.1.
Rysunek 7.1. Interfejsy kolekcji
Interfejsy IEnumerable i IEnumeratorInterfejs IEnumerator definiuje podstawowy niskopoziomowy protokół określający sposób przeglą-dania elementów kolekcji do przodu. Jego deklaracja wygląda tak:
public interface IEnumerator{ bool MoveNext(); object Current { get; } void Reset();}
Metoda MoveNext przesuwa bieżący element zwany kursorem o jedną pozycję dalej i zwraca fałsz,jeśli był to ostatni element tej kolekcji. Metoda Current zwraca bieżący element (zazwyczaj rzutowanyz typu object na bardziej konkretny typ). Metoda MoveNext musi zostać wywołana przed pobraniempierwszego elementu — zasadę tę wprowadzono, aby było możliwe tworzenie pustych kolekcji.Metoda Reset, jeśli jest zaimplementowana, przenosi kursor z powrotem na początek, aby możnabyło od nowa przejrzeć kolekcję. Metoda ta znajduje zastosowanie głównie przy współpracy z tech-nologią COM. Raczej nie wywołuje się jej bezpośrednio, ponieważ nie jest wszędzie obsługiwana(ani niezbędna, gdyż w większości przypadków równie dobrze można utworzyć nowy enumerator).
Tylko nieliczne kolekcje implementują enumeratory. Większość udostępnia enumeratory przezinterfejs IEnumerable:
public interface IEnumerable{ IEnumerator GetEnumerator();}
Dzięki definicji tylko jednej metody zwracającej enumerator interfejs IEnumerable zapewnia ela-styczność umożliwiającą dostarczenie logiki iteracji w innej klasie. Ponadto dzięki temu kolekcjęmoże przeglądać kilku konsumentów jednocześnie i w żaden sposób nie będą sobie przeszkadzać.Interfejs IEnumerable można traktować jak „IEnumeratorProvider” i jest to najbardziej podstawowyinterfejs implementowany przez klasy kolekcji.
Poleć książkęKup książkę
Przeliczalność 291
Poniżej znajduje się przykład niskopoziomowego wykorzystania interfejsów IEnumerable i IEnumerator:string s = "Cze ";
// klasa string implementuje interfejs IEnumerable, wi c mo emy wywo a metod GetEnumerator():IEnumerator rator = s.GetEnumerator();
while (rator.MoveNext()){ char c = (char) rator.Current; Console.Write (c + ".");}
// wynik: C.z.e. . .
Jednak taki bezpośredni sposób wywoływania metod na enumeratorach należy do rzadkości, ponie-waż w języku C# istnieje wygodny skrót składniowy w postaci instrukcji foreach. Oto ten samprzykład napisany z użyciem tej właśnie instrukcji:
string s = "Cze "; // klasa string implementuje interfejs IEnumerable
foreach (char c in s) Console.Write (c + ".");
Interfejsy IEnumerable<T> i IEnumerator<T>Interfejsy IEnumerator i IEnumerable są prawie zawsze implementowane w parze ze swoimi rozszerzo-nymi generycznymi wersjami:
public interface IEnumerator<T> : IEnumerator, IDisposable{ T Current { get; }}
public interface IEnumerable<T> : IEnumerable{ IEnumerator<T> GetEnumerator();}
Dzięki definicjom typizowanych wersji metod Current i GetEnumerator interfejsy te wzmacniająbezpieczeństwo typów, eliminują konieczność pakowania elementów typów wartościowych orazsą wygodniejsze w użyciu. Tablice automatycznie implementują interfejs IEnumerable<T> (gdzie T jesttypem elementów przechowywanych w tablicy).
Dzięki zwiększonemu bezpieczeństwu dla typów wywołanie poniższej metody z tablicą znakówspowoduje błąd kompilacji:
void Test (IEnumerable<int> numbers) { ... }
W klasach kolekcji standardowo udostępnia się publicznie elementy interfejsu IEnumerable<T>,a „ukrywa” elementy niegenerycznego interfejsu IEnumerable przez zastosowanie jawnej implementa-cji tego pierwszego. Dzięki temu, jeśli programista bezpośrednio wywoła metodę GetEnumerator(),to otrzyma bezpieczny pod względem typów IEnumerator<T>. Zdarzają się jednak przypadki złamaniatej zasady ze względu na zgodność ze starym kodem (typy generyczne wprowadzono dopiero w C# 2.0).Dobrym przykładem są tablice, które muszą zwracać niegeneryczny (można ładniej powiedzieć:klasyczny) IEnumerator, aby nie spowodować awarii starych partii kodu. Aby otrzymać generycz-ny IEnumerator<T>, należy dokonać rzutowania, by udostępnić jawny interfejs:
Poleć książkęKup książkę
292 Rozdział 7. Kolekcje
int[] data = { 1, 2, 3 };var rator = ((IEnumerable <int>)data).GetEnumerator();
Na szczęście dzięki instrukcji foreach rzadko jest to konieczne.
Interfejsy IEnumerable<T> i IDisposable
IEnumerator<T> dziedziczy po IDisposable. Dzięki temu enumeratory mogą przechowywać referencjedo takich zasobów jak połączenia z bazą danych i zwalniać je po zakończeniu lub przerwaniu pracy.Instrukcja foreach „ma świadomość” tego szczegółu i tłumaczy taki kod:
foreach (var element in somethingEnumerable) { ... }
na następujący logiczny ekwiwalent:using (var rator = somethingEnumerable.GetEnumerator()) while (rator.MoveNext()) { var element = rator.Current; ... }
Kiedy używać interfejsów niegenerycznychBiorąc pod uwagę zwiększone bezpieczeństwo typowe generycznych interfejsów kolekcji, takich jakIEnumerable<T>, można zadać pytanie: czy niegeneryczna wersja IEnumerable (lub ICollection alboIList) w ogóle jest do czegoś potrzebna?
Jeśli chodzi o interfejs IEnumerable, to musi być implementowany w połączeniu z IEnumerable<T>,ponieważ ten drugi korzysta z pierwszego. Jednak niezmiernie rzadko pisze się implementacje tychinterfejsów od początku — najczęściej można wykorzystać metody iteracyjne, Collection<T> oraz LINQ.
A co z konsumentem? Prawie zawsze wystarczają interfejsy generyczne. Wprawdzie niegeneryczne wersjeteż są czasami przydatne, choć raczej do zapewnienia spójności typów wszystkich elementów kolekcji.Poniższa metoda np. rekurencyjnie liczy elementy w każdej kolekcji:
public static int Count (IEnumerable e){ int count = 0; foreach (object element in e) { var subCollection = element as IEnumerable; if (subCollection != null) count += Count (subCollection); else count++; } return count;}
Ponieważ w języku C# występuje kowariancja interfejsów generycznych, można się spodziewać, że tametoda powinna przyjmować typ IEnumerable<object>. To jednak nie udałoby się z elementamitypów wartościowych i ze starymi kolekcjami, które nie implementują interfejsu IEnumerable<T> —przykładem jest ControlCollection z Windows Forms.
Tak na marginesie: uważny czytelnik mógł zauważyć w naszym przykładzie potencjalny błąd — cyklicznereferencje spowodują nieskończoną rekurencję i awarię metody. Problem ten można łatwo usunąć,używając kolekcji HashSet (zob. sekcję „Klasy HashSet<T> i SortedSet<T>”).
Poleć książkęKup książkę
Przeliczalność 293
Blok using zapewnia odpowiednie załatwienie zasobów — szerzej na temat interfejsu IDisposablepiszemy w rozdziale 12.
Implementowanie interfejsów przeliczeniowychInterfejsy IEnumerable i IEnumerable<T> można zaimplementować z następujących powodów:
aby umożliwić korzystanie z instrukcji foreach;
aby zapewnić możliwość współpracy ze wszystkim, co oczekuje standardowej kolekcji;
aby spełnić wymagania bardziej zaawansowanego interfejsu kolekcji;
aby obsługiwać inicjalizatory kolekcji.
Aby zaimplementować interfejs IEnumerable lub IEnumerable<T>, należy dostarczyć enumerator.Można to zrobić na jeden z trzech sposobów:
jeżeli klasa „opakowuje” inną kolekcję, można zwrócić enumerator tej opakowanej kolekcji;
przez iterator za pomocą instrukcji yield return;
tworząc własną implementację interfejsu IEnumerable lub IEnumerable<T>.
Można też utworzyć podklasę istniejącej kolekcji. Klasa Collection<T> służy właśniedo tego celu (zob. podrozdział „Kolekcje i pośredniki z możliwością dostosowywania”).Inną możliwością jest użycie operatorów zapytań LINQ, o których mowa w następnymrozdziale.
Zwrócenie enumeratora innej kolekcji jest zaledwie kwestią wywołania metody GetEnumerator nawewnętrznej kolekcji. Jednak takie rozwiązanie jest możliwe jedynie w najprostszych przypadkach,gdy elementy wewnętrznej kolekcji są dokładnie tym, czym powinny być. Bardziej elastycznerozwiązanie polega na napisaniu iteratora przy użyciu instrukcji yield return. Iterator to elementjęzyka C# pomocny w pisaniu kolekcji na podobnej zasadzie, jak instrukcja foreach jest pomocnaw ich konsumowaniu. Iterator automatycznie rozwiązuje kwestię implementacji interfejsów IEnumerablei IEnumerator lub ich generycznych wersji. Oto prosty przykład:
public class MyCollection : IEnumerable{ int[] data = { 1, 2, 3 };
public IEnumerator GetEnumerator() { foreach (int i in data) yield return i; }}
Zwróć uwagę na zawartą w tym kodzie „czarną magię” — metoda GetEnumerator nie wygląda tak,jakby miała zwracać enumerator! Kompilator, parsując instrukcję yield return, tworzy ukrytą za-gnieżdżoną klasę enumeratora, a następnie refaktoryzuje metodę GetEnumerator w taki sposób,aby tworzyła i zwracała egzemplarz tej klasy. Iteratory są proste i potężne (i często znajdują zastosowa-nie w implementacji standardowych operatorów zapytań LINQ to Object).
Poleć książkęKup książkę
294 Rozdział 7. Kolekcje
Zgodnie z tą linią możemy też zaimplementować generyczny interfejs IEnumerable<T>:public class MyGenCollection : IEnumerable<int>{ int[] data = { 1, 2, 3 };
public IEnumerator<int> GetEnumerator() { foreach (int i in data) yield return i; }
IEnumerator IEnumerable.GetEnumerator() // jawna implementacja { // ukrywa go return GetEnumerator(); }}
Jako że interfejs IEnumerable<T> dziedziczy po IEnumerable, musimy zaimplementować zarównogeneryczną, jak i niegeneryczną wersję metody GetEnumerator. Dodatkowo zgodnie ze standardowąpraktyką zaimplementowaliśmy też jawnie niegeneryczną wersję. Może ona po prostu wywoływaćgeneryczną metodę GetEnumerator, ponieważ interfejs IEnumerator<T> dziedziczy po IEnumerator.
Napisana przez nas klasa mogłaby zostać wykorzystana jako baza do napisania bardziej zaawanso-wanej kolekcji. Jeśli jednak potrzebna jest tylko prosta implementacja interfejsu IEnumerable<T>,instrukcja yield return umożliwia skorzystanie z prostszego rozwiązania. Zamiast pisać klasę, logikęiteracji można umieścić w metodzie zwracającej generyczną kolekcję typu IEnumerable<T> i resztęzostawić kompilatorowi. Oto przykład:
public class Test{ public static IEnumerable <int> GetSomeIntegers() { yield return 1; yield return 2; yield return 3; }}
A oto przykład użycia naszej metody:foreach (int i in Test.GetSomeIntegers()) Console.WriteLine (i);
// wynik123
Ostatnim sposobem napisania metody GetEnumerator jest napisanie klasy bezpośrednio implementu-jącej interfejs IEnumerator. Dokładnie to robi kompilator niejawnie, przy rozpoznawaniu iteratorów.(Na szczęście nieczęsto trzeba posuwać się tak daleko we własnym kodzie). Poniżej znajduje sięprzykład kolekcji z wpisanymi na stałe wartościami 1, 2 i 3:
public class MyIntList : IEnumerable{ int[] data = { 1, 2, 3 };
Poleć książkęKup książkę
Przeliczalność 295
public IEnumerator GetEnumerator() { return new Enumerator (this); }
class Enumerator : IEnumerator // definicja wewn trznej klasy { // dla enumeratora MyIntList collection; int currentIndex = -1;
public Enumerator (MyIntList collection) { this.collection = collection; }
public object Current { get { if (currentIndex == -1) throw new InvalidOperationException ("Enumeracja nie zosta a rozpocz ta!"); if (currentIndex == collection.data.Length) throw new InvalidOperationException ("Za ko cem listy!"); return collection.data [currentIndex]; } }
public bool MoveNext() { if (currentIndex >= collection.data.Length - 1) return false; return ++currentIndex < collection.data.Length; }
public void Reset() { currentIndex = -1; } }}
Implementacja metody Reset jest nieobowiązkowa — ewentualnie można zgłaszaćwyjątek NotSupportedException.
Podkreślmy, że pierwsze wywołanie metody MoveNext powinno powodować przejście do pierwszego(a nie drugiego) elementu listy.
Aby uzyskać funkcjonalność zbliżoną do iteratora, musimy jeszcze dodatkowo zaimplementować in-terfejs IEnumerator<T>. Poniżej przedstawiamy przykład z pominięciem testów granic dla uproszczenia:
class MyIntList : IEnumerable<int>{ int[] data = { 1, 2, 3 };
// Generyczny enumerator jest zgodny zarówno z IEnumerable, jak i IEnumerable<T>. // Implementujemy niegeneryczn metod GetEnumerator jawnie, aby unikn konfliktów nazw.
public IEnumerator<int> GetEnumerator() { return new Enumerator(this); } IEnumerator IEnumerable.GetEnumerator() { return new Enumerator(this); }
Poleć książkęKup książkę
296 Rozdział 7. Kolekcje
class Enumerator : IEnumerator<int> { int currentIndex = -1; MyIntList collection;
public Enumerator (MyIntList collection) { this.collection = collection; }
public int Current => collection.data [currentIndex];
object IEnumerator.Current => Current;
public bool MoveNext() => ++currentIndex < collection.data.Length;
public void Reset() => currentIndex = -1; // Je li nie jest potrzebna metoda Dispose, to dobrym zwyczajem jest jej // jawne zaimplementowanie tak, aby by a niedost pna w interfejsie publicznym. void IDisposable.Dispose() {} }}
Przykład z użyciem typów generycznych jest szybszy, ponieważ metoda IEnumerator<int>.Currentnie wymaga rzutowania z int na object, a więc eliminuje pakowanie.
Interfejsy ICollection i IListChoć interfejsy enumeracyjne stanowią protokół iteracji kolekcji tylko do przodu, nie zapewniająmożliwości sprawdzania rozmiaru kolekcji, dostępu do składowych za pomocą indeksów, przeszu-kiwania struktur danych ani ich modyfikowania. Wszystkie te funkcje zapewniają interfejsy .NETFramework ICollection, IList oraz IDictionary. Każdy z nich występuje w wersji generycznej i nie-generycznej, choć te drugie istnieją głównie ze względu na zgodność ze starym kodem.
Hierarchia dziedziczenia tych interfejsów jest pokazana na rysunku 7.1. Najprościej można je podsu-mować w następujący sposób:
IEnumerable<T> (i IEnumerable)Zapewnia minimalną funkcjonalność (tylko przeglądanie).
ICollection<T> (i ICollection)Zapewnia średni poziom funkcjonalności (np. własność Count).
IList <T>/IDictionary <K,V> i ich niegeneryczne wersjeZapewnia najwyższy poziom funkcjonalności (wliczając dostęp „swobodny” przy użyciu indek-sów i kluczy).
Konieczność implementowania któregokolwiek z tych interfejsów jest rzadkością.Gdy trzeba napisać klasę kolekcji, to prawie zawsze można wykorzystać do tego klasę ba-zową Collection<T> (zob. podrozdział „Kolekcje i pośredniki z możliwością dostosowy-wania”). W niektórych przypadkach inną możliwość zapewnia też technologia LINQ.
Poleć książkęKup książkę
Interfejsy ICollection i IList 297
Różnice między wersjami generycznymi i niegenerycznymi są większe niż można się spodziewać,zwłaszcza w przypadku interfejsu ICollection. Przyczyny tego są w głównej mierze historyczne — typygeneryczne powstały później, więc interfejsy generyczne tworzono z pewnym bagażem doświadczenia,dzięki czemu udało się dobrać inne (i lepsze) składowe. Dlatego właśnie interfejs ICollection<T> nierozszerza interfejsu ICollection, IList<T> nie rozszerza interfejsu IList, a IDictionary<TKey,TValue> nie rozszerza interfejsu IDictionary. Oczywiście klasa kolekcji może implementować obiewersje interfejsu, jeśli jest to korzystne (a często jest).
Innym, mniej oczywistym powodem, dla którego IList<T> nie rozszerza interfejsuIList, jest to, że rzutowanie na IList<T> zwracałoby interfejs ze składowymi Add(T)i Add(object). To z kolei oznaczałoby zniweczenie bezpieczeństwa typowego, po-nieważ można byłoby wywołać metodę Add z obiektem dowolnego typu.
W tym podrozdziale są opisane interfejsy ICollection<T>, IList<T> i ich niegeneryczne wersje.Opis interfejsów słownikowych znajduje się w podrozdziale „Słowniki”.
W obrębie platformy .NET Framework słowa kolekcja i lista są używane bez dającejsię uchwycić logiki. Na przykład interfejs IList<T> jest bardziej funkcjonalną wersjąinterfejsu ICollection<T>, więc można oczekiwać, że klasa List<T> będzie tak samobardziej funkcjonalna niż klasa Collection<T>. Jednak tak nie jest. Dlatego terminykolekcja i lista najlepiej traktować jako synonimy, chyba że chodzi o konkretny typ.
Interfejsy ICollection<T> i ICollectionICollection<T> to standardowy interfejs dla policzalnych kolekcji obiektów. Zapewnia możliwośćsprawdzenia rozmiaru kolekcji (Count), sprawdzenia, czy dany element znajduje się w kolekcji(Contains), skopiowania kolekcji do tablicy (ToArray) oraz stwierdzenia, czy strukturę można modyfi-kować (IsReadOnly). W przypadku kolekcji z możliwością zapisu dostępne są także operacje Add,Remove i Clear. A ponieważ interfejs ten rozszerza IEnumerable<T>, kolekcje można przeglądać zapomocą instrukcji foreach:
public interface ICollection<T> : IEnumerable<T>, IEnumerable{ int Count { get; }
bool Contains (T item); void CopyTo (T[] array, int arrayIndex); bool IsReadOnly { get; }
void Add(T item); bool Remove (T item); void Clear();}
Niegeneryczny interfejs ICollection także opisuje policzalną kolekcję, ale nie zapewnia funkcjido modyfikowania listy ani sprawdzania, czy zawiera określony element:
public interface ICollection : IEnumerable{ int Count { get; } bool IsSynchronized { get; }
Poleć książkęKup książkę
298 Rozdział 7. Kolekcje
object SyncRoot { get; } void CopyTo (Array array, int index);}
Niegeneryczny interfejs dodatkowo definiuje własności przydatne w synchronizacji (rozdział 14.)— wstawiono je do wersji generycznej, ponieważ bezpieczeństwo wątków nie jest już uważane zacechę wewnętrzną kolekcji.
Implementacja obu interfejsów jest łatwa. W przypadku implementacji interfejsu tylko do odczytuICollection<T> metody Add, Remove i Clear powinny zgłaszać wyjątek NotSupportedException.
Z reguły interfejsy te implementuje się łącznie z IList lub IDictionary.
Interfejsy IList<T> i IListIList<T> to standardowy interfejs kolekcji indeksowanych pozycyjnie. Oprócz składników odziedzi-czonych z interfejsów ICollection<T> i IEnumerable<T> zawiera funkcje pozwalające odczytywać,zapisywać (za pomocą indeksatora), wstawiać oraz usuwać elementy wg pozycji:
public interface IList<T> : ICollection<T>, IEnumerable<T>, IEnumerable{ T this [int index] { get; set; } int IndexOf (T item); void Insert (int index, T item); void RemoveAt (int index);}
Metody IndexOf wykonują przeszukiwanie liniowe listy i zwracają wartość -1, jeśli nie znajdąszukanego elementu.
Niegeneryczna wersja interfejsu IList ma więcej składowych, ponieważ mniej dziedziczy poICollection:
public interface IList : ICollection, IEnumerable{ object this [int index] { get; set } bool IsFixedSize { get; } bool IsReadOnly { get; } int Add (object value); void Clear(); bool Contains (object value); int IndexOf (object value); void Insert (int index, object value); void Remove (object value); void RemoveAt (int index);}
Metoda Add niegenerycznego interfejsu IList zwraca liczbę całkowitą będącą indeksem nowo do-danego elementu. Dla porównania metoda Add interfejsu ICollection<T> ma typ zwrotny void.
Ogólna klasa List<T> jest typową implementacją interfejsów IList<T> i IList. W języku C# takżetablice implementują zarówno generyczną, jak i niegeneryczną wersję (choć metody dodające i usu-wające elementy są ukryte przez jawną implementację interfejsu i w razie wywołania zgłaszająwyjątek NotSupportedException).
Poleć książkęKup książkę
Interfejsy ICollection i IList 299
Przy próbie uzyskania dostępu do wielowymiarowej tablicy za pomocą indeksatorainterfejsu IList zgłaszany jest wyjątek ArgumentException. Jest to pułapka dla progra-mistów piszących takie metody jak poniższa:
public object FirstOrNull (IList list){ if (list == null || list.Count == 0) return null; return list[0];}
Na pierwszy rzut oka może się wydawać, że to bardzo solidna funkcja, ale zgłosiwyjątek, jeśli ktoś wywoła ją na tablicy wielowymiarowej. W razie potrzeby w czasiedziałania programu można testować, czy argument nie jest tablicą wielowymiarową,za pomocą poniższego wyrażenia (szerzej na ten temat piszemy w rozdziale 19.):
list.GetType().IsArray && list.GetType().GetArrayRank()>1
Interfejs IReadOnlyList<T>W celu zapewniania możliwości współpracy z kolekcjami tylko do odczytu Windows Runtimew .NET Framework 4.5 wprowadzono nowy interfejs kolekcji o nazwie IReadOnlyList<T>. Jest onjednak przydatny sam w sobie i można go traktować jak okrojoną wersję interfejsu IList<T> udostęp-niającego tylko składowe potrzebne do wykonywania operacji odczytu na listach:
public interface IReadOnlyList<out T> : IEnumerable<T>, IEnumerable{ int Count { get; } T this[int index] { get; }}
Ponieważ parametr typu jest wykorzystywany wyłącznie na pozycjach wyjściowych, oznaczonogo jako kowariantny. Dzięki temu np. listę kotów można traktować jako listę zwierząt tylko do odczy-tu. Natomiast w interfejsie IList<T> parametr T nie jest oznaczony jako kowariantny, ponieważznajduje zastosowanie zarówno na pozycjach wejściowych, jak i wyjściowych.
Interfejs IReadOnlyList<T> reprezentuje widok listy tylko do odczytu. Nie oznaczato jednak, że podstawowa implementacja także musi być tylko do odczytu.
Zgodnie z logiką interfejs IList<T> powinien dziedziczyć po IReadOnlyList<T>. Jednak firmaMicrosoft nie mogła wprowadzić takiej zmiany, ponieważ wymagałaby ona przeniesienia składowychz IList<T> do IReadOnlyList<T>, co spowodowałoby problemy z programami działającymi podkontrolą CLR 4.5 (konsumenci musieliby ponownie skompilować swoje programy, aby uniknąćbłędów wykonawczych). Dlatego implementatorzy interfejsu IList<T> muszą ręcznie dodawać doswoich kolekcji implementację interfejsu IReadOnlyList<T>.
Interfejs IReadOnlyList<T> odpowiada typowi Windows Runtime IVectorView<T>.
Poleć książkęKup książkę
300 Rozdział 7. Kolekcje
Klasa ArrayKlasa Array to podstawa wszystkich jedno- i wielowymiarowych tablic oraz jeden z podstawowychtypów implementujących standardowe interfejsy kolekcji. Ponieważ zapewnia unifikację typów,wszystkie tablice dysponują takim samym zestawem metod, niezależnie od ich deklaracji i typuelementów.
Ze względu na wielkie znaczenie tablic w języku C# utworzono specjalną składnię do ich deklaro-wania i inicjalizowania, której opis znajduje się w rozdziałach 2. i 3. Gdy programista deklarujetablicę za pomocą składni C#, system CLR niejawnie generuje podtyp klasy Array, tworząc pseudotypo odpowiednich wymiarach i typie elementów. Ten typ implementuje typizowane generyczne inter-fejsy kolekcji, np. IList<string>.
Ponadto system CLR traktuje typy tablicowe w specjalny sposób, przypisując tworzonym obiektomciągły obszar pamięci. Dzięki temu indeksowanie jest bardzo szybkie, ale za cenę braku możliwościzwiększenia rozmiaru struktury w późniejszym czasie.
Klasa Array implementuje interfejsy kolekcji do IList<T> w wersjach generycznych i niegenerycz-nych. Natomiast interfejs IList<T> jest zaimplementowany jawnie w celu utrzymania porządkuw interfejsie publicznym tablicy, który nie może udostępniać takich metod jak Add czy Remove,ponieważ zgłaszają one wyjątki, jeśli wywoła się je na kolekcji o niezmiennym rozmiarze. Wprawdzieklasa Array udostępnia statyczną metodę o nazwie Resize do zmieniania rozmiaru tablicy, ale jejdziałanie polega na utworzeniu nowej tablicy i skopiowaniu do niej wszystkich elementów. Niedość, że ta operacja jest bardziej nieefektywna, to na dodatek wszystkie znajdujące się w różnychmiejscach programu referencje nadal będą wskazywać starą strukturę. Jeśli potrzebny jestobiekt o zmiennym rozmiarze, to lepiej użyć klasy List<T> (opisanej w następnym podrozdziale).
W tablicy można przechowywać elementy typów zarówno wartościowych, jak i referencyjnych.Elementy wartościowe są przechowywane bezpośrednio w tablicy, więc struktura zawierająca trzyliczby całkowite (każda po 8 bajtów) zajmuje ciągły obszar pamięci o rozmiarze 24 bajtów. Natomiastelementy typów referencyjnych zajmują w tablicy tylko tyle miejsca, ile potrzeba do przechowywaniareferencji (4 bajty w środowisku 32-bitowym i 8 bajtów w środowisku 64-bitowym). Na rysunku 7.2pokazano, co dzieje się w pamięci po wykonaniu poniższego programu:
StringBuilder[] builders = new StringBuilder [5];builders [0] = new StringBuilder ("builder1");builders [1] = new StringBuilder ("builder2");builders [2] = new StringBuilder ("builder3");
long[] numbers = new long [3];numbers [0] = 12345;numbers [1] = 54321;
Jako że Array to klasa, same tablice są typami referencyjnymi, niezależnie od rodzaju przechowywa-nych w nich elementów. Oznacza to, że wynikiem wykonania instrukcji tablicaB = tablicaA będziepowstanie dwóch zmiennych odnoszących się do tej samej tablicy. Jednocześnie test równościdwóch różnych tablic zawsze będzie miał wynik negatywny, chyba że programista użyje własnego
Poleć książkęKup książkę
Klasa Array 301
Rysunek 7.2. Tablice w pamięci
komparatora. Jeden taki komparator wprowadzono w .NET Framework 4.0, aby umożliwić porów-nywanie elementów w tablicach lub krotkach. Dostęp do niego można uzyskać przez typ StructuralComparisons:object[] a1 = { "string", 123, true };object[] a2 = { "string", 123, true };
Console.WriteLine (a1 == a2); // fa szConsole.WriteLine (a1.Equals (a2)); // fa sz
IStructuralEquatable se1 = a1;Console.WriteLine (se1.Equals (a2, StructuralComparisons.StructuralEqualityComparer)); // prawda
Tablice można kopiować za pomocą metody Clone: tablicaB = tablicaA.Clone(). Jednak w tensposób można wykonać kopię płytką, czyli obejmującą tylko reprezentowany przez tablicę obszarpamięci. Jeżeli struktura zawiera elementy typów wartościowych, to zostaną one skopiowane. Alejeżeli tablica zawiera obiekty typów referencyjnych, to skopiowane zostaną tylko referencje (w efekciepowstaną dwie tablice, których składowe odnoszą się do tych samych obiektów). Na rysunku 7.3przedstawiono skutek dodania do naszego przykładu poniższego kodu:
StringBuilder[] builders2 = builders;StringBuilder[] shallowClone = (StringBuilder[]) builders.Clone();
Jeśli potrzebna jest kopia głęboka — z duplikatami wszystkich obiektów typu referencyjnego —należy przejrzeć tablicę za pomocą pętli i każdy element sklonować ręcznie. Te same zasady dotyczątakże innych typów kolekcji .NET.
Choć klasa Array jest głównie przeznaczona do pracy z indeksatorami 32-bitowymi, to dzięki kilkumetodom przyjmującym parametry Int32 i Int64 do pewnego stopnia obsługuje także indeksatory64-bitowe (co teoretycznie zwiększa jej przestrzeń adresową do 264 elementów). W praktyce te przecią-żone wersje metod są jednak bezużyteczne, ponieważ maksymalny rozmiar obiektu w systemie CLR— w tym także tablic — wynosi 2 GB (zarówno w środowisku 32-bitowym, jak i 64-bitowym).
Poleć książkęKup książkę
302 Rozdział 7. Kolekcje
Rysunek 7.3. Płytkie kopiowanie tablicy
Wiele z metod klasy Array, które mogą się wydawać metodami egzemplarzowymi,w istocie jest metodami statycznymi. Projektanci tej klasy podjęli dziwną decyzję podtym względem i przez to programista szukający odpowiedniej metody musi sprawdzaćzarówno wśród metod statycznych, jak i egzemplarzowych.
Tworzenie i indeksowanie tablicNajprostszym sposobem na utworzenie i zindeksowanie tablicy jest użycie konstrukcji języka C#:
int[] myArray = { 1, 2, 3 };int first = myArray [0];int last = myArray [myArray.Length - 1];
Ewentualnie tablicę można utworzyć dynamicznie za pomocą metody Array.CreateInstance,która pozwala na określenie typu elementów i liczby wymiarów oraz tworzenie tablic indeksowanychod innego numeru niż zero (przez określenie dolnej granicy). Tablice indeksowane w ten sposóbsą jednak niezgodne z CLS (ang. Common Language Specification).
Dostęp do elementów dynamicznie utworzonej tablicy zapewniają metody GetValue i SetValue(działają też na zwykłych tablicach):
// utworzenie tablicy a cuchów o d ugo ci 2Array a = Array.CreateInstance (typeof(string), 2);a.SetValue ("Witaj,", 0); // a[0] = "Witaj,";a.SetValue (" wiecie", 1); // a[1] = " wiecie";string s = (string) a.GetValue (0); // s = a[0];// istnieje te mo liwo rzutowania na tablice C#string[] cSharpArray = (string[]) a;string s2 = cSharpArray [0];
Tworzone dynamicznie tablice indeksowane od zera można rzutować na tablice C# takiego samegolub zgodnego typu (zgodnego wg zasad wariancji tablic). Jeśli np. klasa Apple jest pochodną klasyFruit, to tablicę typu Apple[] można rzutować na typ Fruit[]. W tym momencie niektórzy mogą
Poleć książkęKup książkę
Klasa Array 303
się zastanawiać, dlaczego do unifikacji tablicy nie użyto typu object[], tylko klasy Array. Przyczynąjest to, że typ object[] jest niezgodny z wielowymiarowymi tablicami typów wartościowych (a takżeindeksowanych nie od zera). Tablicy typu int[] nie można rzutować na object[]. Dlatego potrzebu-jemy klasy Array w celu zapewnienia kompletnej unifikacji.
Metody GetValue i SetValue działają też na tablicach stworzonych przez kompilator oraz są przy-datne przy pisaniu metod działających na tablicach dowolnego typu i rzędu. Dla tablic wielowymia-rowych przyjmują tablicę indeksatorów:
public object GetValue (params int[] indices)public void SetValue (object value, params int[] indices)
Poniższa metoda drukuje pierwszy element tablicy, niezależnie od tego, ile ma ona wymiarów:void WriteFirstValue (Array a){ Console.Write (a.Rank + "-dimensional; ");
// Tablica indeksatorów automatycznie zainicjalizuje wszystkie warto ci zerami, wi c przekazanie // jej do metody GetValue lub SetValue spowoduje pobranie lub ustawienie pierwszego elementu tablicy.
int[] indexers = new int[a.Rank]; Console.WriteLine ("Pierwsza warto to " + a.GetValue (indexers));}
void Demo(){ int[] oneD = { 1, 2, 3 }; int[,] twoD = { {5,6}, {8,9} };
WriteFirstValue (oneD); // jednowymiarowa; pierwsza warto to 1 WriteFirstValue (twoD); // dwuwymiarowa; pierwsza warto to 5}
Do pracy z tablicami nieznanego typu, ale znanego rzędu można zastosować prostszei efektywniejsze rozwiązanie z wykorzystaniem typów generycznych:void WriteFirstValue<T> (T[] array){ Console.WriteLine (array[0]);}
Metoda SetValue zgłasza wyjątek, jeżeli element jest nieodpowiedniego dla danej tablicy typu.
Gdy tworzona jest tablica, zarówno za pomocą składni języka, jak i metody Array.CreateInstance,jej elementy zostają automatycznie zainicjalizowane. Jeżeli elementy są typu referencyjnego, począt-kowo przypisywana jest im wartość null. Natomiast w przypadku elementów typów wartościowychzostaje wywołany konstruktor domyślny odpowiedniego typu (co w istocie oznacza wyzerowanieskładowych). Ponadto klasa Array zawiera metodę Clear, za pomocą której w dowolnym mo-mencie można wyzerować tablicę:
public static void Clear (Array array, int index, int length);
Metoda ta nie zmienia rozmiaru tablicy, co kłóci się z jej typowym zastosowaniem (np. w ICollection<T>.Clear), polegającym na redukcji struktury do zera elementów.
Poleć książkęKup książkę
304 Rozdział 7. Kolekcje
Przeglądanie zawartości tablicyZawartość tablicy można łatwo przejrzeć za pomocą instrukcji foreach:
int[] myArray = { 1, 2, 3};foreach (int val in myArray)Console.WriteLine (val);
Ewentualnie można też użyć statycznej metody Array.ForEach o następującej definicji:public static void ForEach<T> (T[] array, Action<T> action);
Wykorzystuje ona delegat Action o następującej sygnaturze:public delegate void Action<T> (T obj);
Tak wygląda pierwszy przykład napisany z użyciem metody Array.ForEach:Array.ForEach (new[] { 1, 2, 3 }, Console.WriteLine);
Długość i liczba wymiarów tablicyW klasie Array dostępne są następujące metody i własności do sprawdzania długości i liczby wymia-rów tablicy:
public int GetLength (int dimension);public long GetLongLength (int dimension);
public int Length { get; }public long LongLength { get; }
public int GetLowerBound (int dimension);public int GetUpperBound (int dimension);
public int Rank { get; } // zwraca liczb wymiarów tablicy
Metody GetLength i GetLongLength zwracają długość wybranego wymiaru (0, jeśli tablica jest jedno-wymiarowa), natomiast metody Length i LongLength zwracają liczbę wszystkich elementów tablicyz wszystkich wymiarów łącznie.
Metody GetLowerBound i GetUpperBound służą do pracy z tablicami indeksowanymi od innego numeruniż zero. Metoda GetUpperBound zwraca wynik równy sumie wartości GetLowerBound i GetLengthdla wybranego wymiaru.
Przeszukiwanie tablicKlasa Array udostępnia bogaty wybór metod do znajdowania elementów w tablicach jednowymia-rowych:
Metody BinarySearchDo szybkiego szukania elementu w posortowanej tablicy.
Metody IndexOf/LastIndexDo szukania elementu w nieposortowanej tablicy.
Find, FindLast, FindIndex, FindLastIndex, FindAll, Exists, TrueForAllDo szukania w nieposortowanych tablicach elementów spełniających warunek Predicate<T>.
Poleć książkęKup książkę
Klasa Array 305
Żadna z metod przeszukujących nie zgłasza wyjątku, jeśli nie znajdzie szukanej wartości. Zamiasttego metody zwracające liczbę całkowitą zwracają -1 (dla tablic indeksowanych od zera), a metodyzwracające typ generyczny zwracają domyślną wartość tego typu (np. 0 w przypadku int i nullw przypadku string).
Metody przeszukiwania binarnego są szybkie, ale działają tylko na posortowanych tablicach i wyma-gają porównywania elementów pod względem kolejności, a nie równości. W efekcie metody te przyj-mują obiekty typu IComparer i IComparer<T> określające definicję porządku w danym przypadku(zob. sekcję „Dołączanie protokołów równości i porządkowania”). Definicja ta musi być zgodnaz komparatorem użytym pierwotnie do posortowania tablicy. Jeżeli nie zostanie przekazany żadenkomparator, zostanie zastosowany domyślny algorytm porządkujący dla danego typu oparty na jegoimplementacji interfejsu IComparable/IComparable<T>.
Metody IndexOf i LastIndexOf służą do prostego przeglądania elementów tablicy i zwracają numerpierwszej (lub ostatniej) pozycji podanej wartości.
Metody działające na bazie predykatów przyjmują delegaty i wyrażenia lambda pozwalającestwierdzić, czy dana wartość „pasuje” do szukanej. Predykat to po prostu delegat przyjmującyobiekt i zwracający prawdę lub fałsz:
public delegate bool Predicate<T> (T object);
W poniższym przykładzie szukamy w tablicy łańcuchów imienia zawierającego literę a:static void Main(){ string[] names = { "Robert", "Jacek", "Juliusz" }; string match = Array.Find (names, ContainsA); Console.WriteLine (match); // Jacek}static bool ContainsA (string name) { return name.Contains ("a"); }
To jest ten sam kod, tylko skrócony dzięki użyciu metody anonimowej:string[] names = { "Robert", "Jacek", "Juliusz" };string match = Array.Find (names, delegate (string name) { return name.Contains ("a"); } );
Wyrażenie lambda pozwala jeszcze bardziej skrócić kod:string[] names = { "Robert", "Jacek", "Juliusz" };string match = Array.Find (names, n => n.Contains ("a")); // Jacek
Metoda FindAll zwraca tablicę wszystkich elementów spełniających warunek predykatu. Metodata, równoznaczna z Enumerable.Where z przestrzeni nazw System.Linq, zwraca tylko tablicę pasującychelementów, a nie obiekt typu IEnumerable<T>.
Metoda Exists zwraca prawdę, jeżeli którykolwiek element tablicy spełnia warunki danego predykatu,i jest równoważna metodzie Any z System.Linq.Enumerable.
Metoda TrueForAll zwraca prawdę, jeżeli wszystkie elementy spełniają warunek predykatu, i jestrównoważna z All z System.Linq.Enumerable.
Poleć książkęKup książkę
306 Rozdział 7. Kolekcje
SortowanieKlasa Array ma następujące wbudowane metody sortujące:
// do sortowania pojedynczej tablicy
public static void Sort<T> (T[] array);public static void Sort (Array array);
// do sortowania pary tablic
public static void Sort<TKey,TValue> (TKey[] keys, TValue[] items);public static void Sort (Array keys, Array items);
Każda z tych metod jest dodatkowo przeciążona i przyjmuje:int index // indeks, od którego ma by rozpocz te sortowanieint length // liczba elementów do posortowaniaIComparer<T> comparer // obiekt definiuj cy sposób porównywaniaComparison<T> comparison // delegat definiuj cy sposób porównywania
Poniżej znajduje się najprostszy przykład użycia metody Sort:int[] numbers = { 3, 2, 1 };Array.Sort (numbers); // teraz tablica ma warto ci { 1, 2, 3 }
Metody przyjmujące pary tablic przekładają elementy w każdej z tablic łącznie i opierają decyzjeporządkowe na pierwszej tablicy. W następnym przykładzie zarówno liczby, jak i odpowiadające imsłowa są sortowane w porządku numerycznym:
int[] numbers = { 3, 2, 1 };string[] words = { "trzy", "dwa", "jeden" };Array.Sort (numbers, words);
// teraz kolejno elementów w tablicy numbers to { 1, 2, 3 }// teraz kolejno elementów w tablicy words to { "jeden", "dwa", "trzy" }
Metoda Array.Sort wymaga, aby znajdujące się w tablicy elementy implementowały interfejsIComparable (zob. podrozdział „Określanie kolejności” w rozdziale 6.). Oznacza to, że większośćwbudowanych typów języka C# (takich jak użyte w poprzednim przykładzie liczby całkowite) możnasortować. Jeżeli elementy nie mają określonego wewnętrznego porządku albo programista chcezmienić domyślną kolejność, konieczne jest przekazanie metodzie Sort własnego dostawcy comparisonokreślającego względne ustawienie dwóch elementów. Można to zrobić na dwa sposoby:
przy użyciu pomocniczego obiektu implementującego interfejs IComparer/Icomparer<T> (zob.podrozdział „Dołączanie protokołów równości i porządkowania”);
przy użyciu delegatu Comparison:public delegate int Comparison<T> (T x, T y);
Delegat Comparison posługuje się taką samą semantyką jak metoda IComparer<T>.CompareTo: jeślix jest przed y, zostaje zwrócona ujemna liczba całkowita; jeśli x jest za y, zostaje zwrócona dodatnialiczba całkowita; jeśli x i y zajmują to samo miejsce, zostaje zwrócone 0.
W poniższym przykładzie sortujemy tablicę liczb całkowitych w taki sposób, że najpierw ustawianesą liczby nieparzyste:
Poleć książkęKup książkę
Klasa Array 307
int[] numbers = { 1, 2, 3, 4, 5 };Array.Sort (numbers, (x, y) => x % 2 == y % 2 ? 0 : x % 2 == 1 ? -1 : 1);// zawarto tablicy numbers to { 1, 3, 5, 2, 4 }
Zamiast metody Sort można też użyć operatorów LINQ OrderBy i ThenBy. W odróż-nieniu od metody Array.Sort operatory LINQ nie zmieniają pierwotnej tablicy, tylkowysyłają posortowane wyniki do nowej sekwencji IEnumerable<T>.
Odwracanie kolejności elementówPoniższe metody klasy Array odwracają kolejność wszystkich lub niektórych elementów tablicy:
public static void Reverse (Array array);public static void Reverse (Array array, int index, int length);
KopiowanieKlasa Array zawiera cztery metody do kopiowania płytkiego: Clone, CopyTo, Copy oraz ConstrainedCopy.Dwie pierwsze są metodami egzemplarzowymi, a pozostałe — statycznymi.
Metoda Clone zwraca nową tablicę (stanowiącą płytką kopię oryginału). Metody CopyTo i Copykopiują ciągły podzbiór elementów tablicy. Kopiowanie wielowymiarowej prostokątnej tablicywymaga przeprowadzenia mapowania wielowymiarowych indeksów na liniowe. Na przykład środko-wy element (position[1,1]) w tablicy o wymiarach 3×3 ma indeks 4, który wynika z obliczeń 1*3+1.Zakresy źródłowy i docelowy mogą się bez problemu nakładać.
Metoda ConstrainedCopy wykonuje operację atomową, tzn. jeśli nie można skopiować wszystkichpotrzebnych elementów (np. z powodu błędnego typu), to cała operacja jest wycofywana.
Ponadto klasa Array zawiera metodę AsReadOnly, która zwraca opakowanie uniemożliwiające ponowneprzypisywanie wartości elementom.
Konwertowanie i zmienianie rozmiarów tablicMetoda Array.ConvertAll tworzy i zwraca nową tablicę typu TOutput. Wywołuje w tym celu przeka-zany jej delegat Converter. Jej definicja wygląda następująco:
public delegate TOutput Converter<TInput,TOutput> (TInput input)
Poniżej znajduje się przykład konwersji tablicy liczb zmiennoprzecinkowych na tablicę liczb całko-witych:
float[] reals = { 1.3f, 1.5f, 1.8f };int[] wholes = Array.ConvertAll (reals, r => Convert.ToInt32 (r));
// zawarto tablicy wholes to { 1, 2, 2 }
Metoda Resize tworzy nową tablicę i kopiuje do niej wszystkie elementy, a następnie zwraca tę nowąstrukturę przez parametr referencyjny. Mimo to referencje do pierwotnej tablicy przechowywanew innych obiektach pozostają niezmienione.
Poleć książkęKup książkę
308 Rozdział 7. Kolekcje
Przestrzeń System.Linq zawiera dodatkowy asortyment metod do konwersji tablic.Wszystkie one zwracają obiekty typu IEnumerable<T>, który można przekonwertowaćna tablicę za pomocą metody ToArray z klasy Enumerable.
Listy, kolejki, stosy i zbioryPlatforma zapewnia podstawowy zestaw konkretnych klas kolekcji implementujących opisanewcześniej interfejsy. W tym podrozdziale skupiamy się na kolekcjach listowych (których nie należymylić ze strukturami słownikowymi opisanymi w podrozdziale „Słowniki”). Tak jak w przypadkuopisanych wcześniej interfejsów, często mamy do wyboru zarówno generyczne, jak i niegenerycznewersje każdego typu. Pod względem elastyczności i wydajności lepsze są klasy generyczne, przezco ich niegeneryczne odpowiedniki są w zasadzie niepotrzebne z wyjątkiem sytuacji, kiedy trzebazapewnić zgodność ze starym kodem. Jest więc inaczej niż w przypadku interfejsów kolekcji, którebywają przydatne także w wersjach niegenerycznych.
Z opisanych w tym podrozdziale klas najczęściej używana jest generyczna klasa List.
Klasy List<T> i ArrayListGeneryczna klasa List i niegeneryczna klasa ArrayList umożliwiają tworzenie tablic obiektów o dy-namicznym rozmiarze i należą do najczęściej używanych klas kolekcji. Klasa ArrayList implementujeinterfejs IList, podczas gdy List<T> implementuje zarówno IList, jak i IList<T> (jak również nowąwersję tylko do odczytu o nazwie IReadOnlyList<T>). Inaczej niż w przypadku tablic, wszystkieinterfejsy są zaimplementowane publicznie i zgodnie z oczekiwaniami metody takie jak Add czy Removesą dostępne.
Wewnętrznie klasy List<T> i ArrayList utrzymują tablicę obiektów, którą w razie osiągnięciamaksimum pojemności zamieniają na większą. Dodawanie elementów na końcu to efektywnaoperacja (ponieważ zazwyczaj na końcu jest wolne miejsce), natomiast wstawianie elementów w środ-ku pomiędzy innymi elementami może być powolne (ponieważ trzeba przesunąć wszystkie elementyznajdujące się za miejscem wstawiania). Jeśli chodzi o przeszukiwanie, to podobnie jak w przypadkutablic operacja jest efektywna, jeżeli przeprowadza się ją za pomocą metody BinarySearch na posorto-wanej liście. W innych sytuacjach wyszukiwanie jest mało wydajne, gdyż wymaga sprawdzenia każ-dego elementu po kolei.
Klasa List<T> jest do kilku razy szybsza od ArrayList, gdy T jest typem wartościo-wym, ponieważ List<T> nie wymaga pakowania ani odpakowywania elementów.
Klasy List<T> i ArrayList zawierają konstruktory przyjmujące istniejące kolekcje elementów —kopiują one wszystkie elementy z przekazanej kolekcji do nowej struktury:
public class List<T> : IList<T>, IReadOnlyList<T>{ public List (); public List (IEnumerable<T> collection); public List (int capacity);
Poleć książkęKup książkę
Listy, kolejki, stosy i zbiory 309
// Add+Insert public void Add (T item); public void AddRange (IEnumerable<T> collection); public void Insert (int index, T item); public void InsertRange (int index, IEnumerable<T> collection);
// Remove public bool Remove (T item); public void RemoveAt (int index); public void RemoveRange (int index, int count); public int RemoveAll (Predicate<T> match);
// indeksowanie public T this [int index] { get; set; } public List<T> GetRange (int index, int count); public Enumerator<T> GetEnumerator();
// eksportowanie, kopiowanie i konwertowanie public T[] ToArray(); public void CopyTo (T[] array); public void CopyTo (T[] array, int arrayIndex); public void CopyTo (int index, T[] array, int arrayIndex, int count); public ReadOnlyCollection<T> AsReadOnly(); public List<TOutput> ConvertAll<TOutput> (Converter <T,TOutput> converter);
// inne public void Reverse(); // odwraca kolejno elementów listy public int Capacity { get;set; } // wymusza rozszerzenie wewn trznej tablicy public void TrimExcess(); // obcina wewn trzn tablic do potrzebnego rozmiaru public void Clear(); // usuwa wszystkie elementy, tak e Count=0}public delegate TOutput Converter <TInput, TOutput> (TInput input);
Oprócz tych składowych klasa List<T> zawiera egzemplarzowe wersje wszystkich metod przeszuki-wania i sortowania klasy Array.
Poniżej znajduje się przykład demonstrujący sposób użycia własności i metod klasy List. Przykładyprzeszukiwania i sortowania zamieściliśmy w podrozdziale „Klasa Array”.
List<string> words = new List<string>(); // nowa lista typu string
words.Add ("melon");words.Add ("awokado");words.AddRange (new[] { "banan", "pomara cza" } );words.Insert (0, "liczi"); // wstawianie na pocz tkuwords.InsertRange (0, new[] { "pomelo", "nashi" }); // wstawianie na pocz tku
words.Remove ("melon");words.RemoveAt (3); // usuni cie czwartego elementuwords.RemoveRange (0, 2); // usuni cie dwóch pierwszych elementów
// usuni cie wszystkich a cuchów zaczynaj cych si liter 'n'words.RemoveAll (s => s.StartsWith ("n"));
Console.WriteLine (words [0]); // pierwsze s owoConsole.WriteLine (words [words.Count - 1]); // ostatnie s owoforeach (string s in words) Console.WriteLine (s); // wszystkie s owaList<string> subset = words.GetRange (1, 2); // drugie i trzecie s owo
Poleć książkęKup książkę
310 Rozdział 7. Kolekcje
string[] wordsArray = words.ToArray(); // tworzy now tablic typizowan
// kopiowanie pierwszych dwóch elementów na koniec istniej cej tablicystring[] existing = new string [1000];words.CopyTo (0, existing, 998, 2);
List<string> upperCastWords = words.ConvertAll (s => s.ToUpper());List<int> lengths = words.ConvertAll (s => s.Length);
Niegeneryczna klasa ArrayList jest wykorzystywana głównie ze względu na zgodność z kodem napi-sanym dla platformy 1.x. Używający jej programista musi się posługiwać niezręcznymi rzutowaniami,jak pokazano w poniższym przykładzie:
ArrayList al = new ArrayList();al.Add ("hello");string first = (string) al [0];string[] strArr = (string[]) al.ToArray (typeof (string));
Kompilator nie może zweryfikować takich operacji rzutowania, przez co np. poniższy kod przejdziekompilację i spowoduje awarię podczas wykonywania programu:
int first = (int) al [0]; // wyj tek wykonawczy
Klasa ArrayList pod względem funkcjonalności przypomina List<object>. Obieprzydają się, gdy potrzebna jest lista elementów różnego typu niemających wspólnegotypu bazowego (innego niż object). Klasa ArrayList może być lepszym wyborem,gdy podczas pracy z listą używa się refleksji (rozdział 19.). Techniki refleksji łatwiejjest stosować w odniesieniu do niegenerycznego typu ArrayList niż do typu generycz-nego List<object>.
Jeśli do programu zaimportuje się przestrzeń nazw System.Linq, to listę ArrayList można przekon-wertować na listę generyczną za pomocą metod Cast i ToList:
ArrayList al = new ArrayList();al.AddRange (new[] { 1, 5, 9 } );List<int> list = al.Cast<int>().ToList();
Cast i ToList to metody rozszerzeniowe klasy System.Linq.Enumerable.
Klasa LinkedList<T>Generyczna klasa LinkedList<T> stanowi implementację listy powiązanej dwustronnie (rysunek 7.4).Lista powiązana dwustronnie to łańcuch węzłów, w którym każdy węzeł zawiera referencję dopoprzedniego i następnego węzła oraz do samego siebie. Największą zaletą tej struktury jest to, żekażdy element można efektywnie wstawić w dowolnym miejscu listy, ponieważ wymaga to tylkoutworzenia nowego węzła i zaktualizowania kilku referencji. Jednak znalezienie miejsca do wsta-wienia elementu może być czasochłonne, ponieważ nie istnieje żaden mechanizm bezpośredniegoindeksowania takiej listy. Trzeba się przyjrzeć każdemu węzłowi i nie można korzystać z algorytmówwyszukiwania binarnego.
Poleć książkęKup książkę
Listy, kolejki, stosy i zbiory 311
Rysunek 7.4. Klasa LinkedList<T>
Klasa LinkedList<T> implementuje interfejsy IEnumerable<T> i ICollection<T> (oraz ich niegene-ryczne wersje). Nie implementuje natomiast interfejsu IList<T>, ponieważ nie obsługuje dostępudo elementów za pomocą indeksów. Implementacja węzłów ma postać następującej klasy:
public sealed class LinkedListNode<T>{ public LinkedList<T> List { get; } public LinkedListNode<T> Next { get; } public LinkedListNode<T> Previous { get; } public T Value { get; set; }}
Nowy węzeł można dodać na pozycji określonej względem innego węzła lub na początku albo na koń-cu listy. W klasie LinkedList<T> znajdują się następujące metody do wykonywania takich operacji:
public void AddFirst(LinkedListNode<T> node);public LinkedListNode<T> AddFirst (T value);
public void AddLast (LinkedListNode<T> node);public LinkedListNode<T> AddLast (T value);
public void AddAfter (LinkedListNode<T> node, LinkedListNode<T> newNode);public LinkedListNode<T> AddAfter (LinkedListNode<T> node, T value);
public void AddBefore (LinkedListNode<T> node, LinkedListNode<T> newNode);public LinkedListNode<T> AddBefore (LinkedListNode<T> node, T value);
Istnieje też podobny zestaw metod do usuwania elementów:public void Clear();
public void RemoveFirst();public void RemoveLast();
public bool Remove (T value);public void Remove (LinkedListNode<T> node);
Poleć książkęKup książkę
312 Rozdział 7. Kolekcje
Klasa LinkedList<T> zawiera też kilka wewnętrznych pól do rejestrowania liczby przechowywanychelementów oraz referencji do pierwszego i ostatniego elementu. Pola te są dostępne w postaci nastę-pujących publicznych własności:
public int Count { get; } // szybkiepublic LinkedListNode<T> First { get; } // szybkiepublic LinkedListNode<T> Last { get; } // szybkie
Dodatkowo klasa LinkedList<T> udostępnia następujące metody wyszukiwania (każda wymaga, abylista była wewnętrznie przeliczalna):
public bool Contains (T value);public LinkedListNode<T> Find (T value);public LinkedListNode<T> FindLast (T value);
Ponadto klasa LinkedList<T> obsługuje kopiowanie elementów do tablicy, aby można się byłoposługiwać indeksami, oraz umożliwia tworzenie enumeratorów, aby można się było posługiwaćpętlą foreach:
public void CopyTo (T[] array, int index);public Enumerator<T> GetEnumerator();
Oto przykład użycia klasy LinkedList<string>:var tune = new LinkedList<string>();tune.AddFirst ("do"); // dotune.AddLast ("sol"); // do - sol
tune.AddAfter (tune.First, "re"); // do - re - soltune.AddAfter (tune.First.Next, "mi"); // do - re - mi - soltune.AddBefore (tune.Last, "fa"); // do - re - mi - fa - sol
tune.RemoveFirst(); // re - mi - fa - soltune.RemoveLast(); // re - mi - fa
LinkedListNode<string> miNode = tune.Find ("mi");tune.Remove (miNode); // re - fatune.AddFirst (miNode); // mi - re - fa
foreach (string s in tune) Console.WriteLine (s);
Klasy Queue<T> i QueueKlasy Queue<T> i Queue to struktury danych typu FIFO (ang. first-in, first-out — pierwszy na wejściu,pierwszy na wyjściu) udostępniające m.in. metody Enqueue (do dodawania elementów na końcukolejki) i Dequeue (do pobierania i usuwania elementów z początku kolejki). Ponadto dostępnajest metoda Peek zwracająca element z początku struktury bez jego usuwania oraz własność Countumożliwiająca sprawdzenie przed zdejmowaniem elementów, czy jakieś w ogóle istnieją.
Choć kolejki są przeliczalne, nie implementują interfejsów IList<T> ani IList, ponieważ do skła-dowych nie można odwoływać się bezpośrednio za pomocą indeksów. W razie potrzeby dostępnajest jednak metoda ToArray służąca do kopiowania elementów do tablicy zapewniającej swobodnydostęp do swojej zawartości:
public class Queue<T> : IEnumerable<T>, ICollection, IEnumerable{
Poleć książkęKup książkę
Listy, kolejki, stosy i zbiory 313
public Queue(); public Queue (IEnumerable<T> collection); // kopiuje istniej ce elementy public Queue (int capacity); // pozwala ograniczy automatyczne zmiany rozmiaru public void Clear(); public bool Contains (T item); public void CopyTo (T[] array, int arrayIndex); public int Count { get; } public T Dequeue(); public void Enqueue (T item); public Enumerator<T> GetEnumerator(); // aby mo na by o korzysta z p tli foreach public T Peek(); public T[] ToArray(); public void TrimExcess();}
Poniżej przedstawiamy przykład użycia klasy Queue<int>:var q = new Queue<int>();q.Enqueue (10);q.Enqueue (20);int[] data = q.ToArray(); // eksport zawarto ci do tablicyConsole.WriteLine (q.Count); // "2"Console.WriteLine (q.Peek()); // "10"Console.WriteLine (q.Dequeue()); // "10"Console.WriteLine (q.Dequeue()); // "20"Console.WriteLine (q.Dequeue()); // spowoduje zg oszenie wyj tku (pusta kolejka)
Wewnętrzna implementacja kolejek opiera się na tablicy, której rozmiar jest zmieniany zgodniez zapotrzebowaniem — podobną implementację ma generyczna klasa List. Kolejka utrzymujeindeksy wskazujące bezpośrednio na pierwszy i ostatni element, dzięki czemu operacje dokładaniai wyjmowania elementów są bardzo szybkie (z wyjątkiem sytuacji, gdy spowodują zmianę rozmiarustruktury).
Klasy Stack<T> i StackKlasy Stack<T> i Stack to struktury danych typu LIFO (ang. last-in, first-out — ostatni na wejściu,pierwszy na wyjściu) udostępniające m.in. metody Push (do dodawania elementu na wierzchu stosu)i Pop (do pobierania i usuwania elementów z wierzchu stosu). Dostępne są też niedestrukcyjnametoda Peek, jak również własność Count i metoda ToArray, umożliwiające eksport danych dostruktury pozwalającej na ich swobodne przeglądanie:
public class Stack<T> : IEnumerable<T>, ICollection, IEnumerable{ public Stack(); public Stack (IEnumerable<T> collection); // kopiuje istniej ce elementy public Stack (int capacity); // pozwala ograniczy automatyczne zmiany rozmiaru public void Clear(); public bool Contains (T item); public void CopyTo (T[] array, int arrayIndex); public int Count { get; } public Enumerator<T> GetEnumerator(); // aby mo na by o korzysta z p tli foreach public T Peek(); public T Pop(); public void Push (T item); public T[] ToArray(); public void TrimExcess();}
Poleć książkęKup książkę
314 Rozdział 7. Kolekcje
Poniżej znajduje się przykład użycia klasy Stack<int>:var s = new Stack<int>();s.Push (1); // s = 1s.Push (2); // s = 1,2s.Push (3); // s = 1,2,3Console.WriteLine (s.Count); // drukuje 3Console.WriteLine (s.Peek()); // drukuje 3, s = 1,2,3Console.WriteLine (s.Pop()); // drukuje 3, s = 1,2Console.WriteLine (s.Pop()); // drukuje 2, s = 1Console.WriteLine (s.Pop()); // drukuje 1, s = <empty>Console.WriteLine (s.Pop()); // powoduje wyj tek
Wewnętrzna implementacja stosów bazuje na tablicy, której rozmiar zmienia się w razie potrzeby,podobnie jak w przypadku klas Queue<T> i List<T>.
Klasa BitArrayKlasa BitArray to kolekcja wartości typu bool z możliwością dynamicznej zmiany rozmiaru. Pozwalaefektywniej wykorzystać pamięć niż zwykła tablica lub struktura List wartości typu bool, ponieważdo przechowywania każdego elementu potrzebuje tylko jednego bitu, podczas gdy normalnie wartośćtypu bool zajmuje jeden bajt.
Indeksator struktury BitArray odczytuje i zapisuje pojedyncze bity:var bits = new BitArray(2);bits[1] = true;
Dostępne są cztery metody bitowe: And, Or, Xor oraz Not. Wszystkie oprócz ostatniej przyjmująobiekty typu BitArray:
bits.Xor (bits); // bitowe lub wykluczaj ce na samym sobieConsole.WriteLine (bits[1]); // fa sz
Klasy HashSet<T> i SortedSet<T>Klasy HashSet<T> i SortedSet<T> to generyczne kolekcje, które wprowadzono odpowiednio w .NETFramework 3.5 i 4.0. Obie wyróżniają się następującymi cechami:
Metody Contains charakteryzują się dużą szybkością działania dzięki posługiwaniu się algoryt-mem wyszukiwania wykorzystującym wartości skrótu.
Nie przechowują duplikatów i niepostrzeżenie ignorują żądania dodania elementów takich sa-mych jak elementy istniejące.
Nie ma możliwości odwołania się do elementu po jego pozycji.
Klasa SortedSet<T> przechowuje elementy w określonym porządku, a HashSet<T> nie przechowuje.
Wspólne cechy tych dwóch klas są dziełem implementacji interfejsu ISet<T>.
Z powodów historycznych klasa HashSet<T> znajduje się w zestawie System.Core.dll,a klasa SortedSet<T> i interfejs ISet<T> w zestawie System.dll.
Poleć książkęKup książkę
Listy, kolejki, stosy i zbiory 315
Implementację klasy HashSet<T> stanowi tablica skrótów przechowująca tylko klucze. Natomiaststruktura SortedSet<T> jest zaimplementowana jako drzewo czerwono-czarne.
Obie kolekcje implementują interfejs ICollection<T> i udostępniają metody, jakich można się spo-dziewać, a więc np.: Contains, Add i Remove. Dodatkowo istnieje też wykorzystująca predykat metodaRemoveWhere do usuwania elementów.
Poniżej przedstawiamy przykład utworzenia zbioru HashSet<char> z istniejącej kolekcji, sprawdzenia,czy wybrany element jest dostępny w zbiorze, oraz jej przejrzenia (zwróć uwagę na usunięcieduplikatów):
var letters = new HashSet<char> ("gdyby kózka nie skaka a");
Console.WriteLine (letters.Contains ('g')); // prawdaConsole.WriteLine (letters.Contains ('j')); // fa sz
foreach (char c in letters) Console.Write (c); // gdyb kózanies
(Przekazanie obiektu typu string do konstruktora klasy HashSet<char> nie spowodowało błędu,ponieważ klasa string implementuje interfejs IEnumerable<char>).
Najciekawsze metody to te operujące na zbiorach. Poniższe metody mają charakter destrukcyjnyw tym sensie, że modyfikują zbiór:
public void UnionWith (IEnumerable<T> other); // dodajepublic void IntersectWith (IEnumerable<T> other); // usuwapublic void ExceptWith (IEnumerable<T> other); // usuwapublic void SymmetricExceptWith (IEnumerable<T> other); // usuwa
Natomiast te metody tylko sprawdzają coś w zbiorze, więc nie mają charakteru destrukcyjnego:public bool IsSubsetOf (IEnumerable<T> other);public bool IsProperSubsetOf (IEnumerable<T> other);public bool IsSupersetOf (IEnumerable<T> other);public bool IsProperSupersetOf (IEnumerable<T> other);public bool Overlaps (IEnumerable<T> other);public bool SetEquals (IEnumerable<T> other);
Metoda UnionWith dodaje wszystkie elementy z drugiego zbioru do pierwszego (wykluczając duplikaty).Metoda IntersectWith usuwa elementy, których nie ma w obu zbiorach. Z naszego zbioru znakówmożemy np. wydobyć wszystkie samogłoski w następujący sposób:
var letters = new HashSet<char> ("gdyby kózka nie skaka a");letters.IntersectWith ("aeioóuy");foreach (char c in letters) Console.Write (c); // yóaie
Metoda ExceptWith usuwa określone elementy ze zbioru źródłowego. W poniższym przykładzie pozba-wiamy nasz zbiór wszystkich samogłosek:
var letters = new HashSet<char> ("gdyby kózka nie skaka a");letters.ExceptWith ("aeioóu");foreach (char c in letters) Console.Write (c); // gdb kzns
Metoda SymmetricExceptWith usuwa wszystkie elementy oprócz tych, które występują tylko w jednymlub drugim zbiorze:
Poleć książkęKup książkę
316 Rozdział 7. Kolekcje
var letters = new HashSet<char> ("gdyby kózka nie skaka a");letters.SymmetricExceptWith ("toby nogi nie z ama a");foreach (char c in letters) Console.Write (c); // dkóstom
Ponieważ klasy HashSet<T> i SortedSet<T> implementują interfejs IEnumerable<T>, ich metodyprzyjmują jako argumenty inne typy zbiorów (lub kolekcji).
Klasa SortedSet<T> ma wszystkie składowe klasy HashSet<T> oraz dodatkowo:public virtual SortedSet<T> GetViewBetween (T lowerValue, T upperValue)public IEnumerable<T> Reverse()public T Min { get; }public T Max { get; }
Ponadto konstruktor klasy SortedSet<T> opcjonalnie przyjmuje obiekt typu IComparer<T> (a nie kom-parator równości).
Oto jeden z efektów załadowania naszego przykładowego ciągu liter do zbioru SortedSet<char>:var letters = new SortedSet<char> ("gdyby kózka nie skaka a");foreach (char c in letters) Console.Write (c); // abdegiknsyzó
Teraz możemy pobrać wszystkie litery z przedziału od f do j:foreach (char c in letters.GetViewBetween ('f', 'j'))Console.Write (c); // gi
SłownikiSłownik jest kolekcją, w której każdy przechowywany element stanowi parę klucz – wartość. Tegotypu struktur danych najczęściej używa się do przeszukiwania i sortowania list.
Platforma .NET zawiera definicję standardowego protokołu słownikowego w postaci interfejsówIDictionary i IDictionary<TKey, TValue> oraz definicji kilku klas słownikowych ogólnego przezna-czenia. Różnią się one między sobą następującymi cechami:
niektóre sortują elementy, a inne nie;
niektóre pozwalają na dostęp do elementów wg pozycji (indeksu) i klucza, a inne nie;
niektóre są generyczne, a inne nie;
niektóre pozwalają na szybkie pobieranie elementów wg klucza dużych słowników, a inne nie.
W tabeli 7.1 przedstawiono zestawienie klas słownikowych i dzielących je różnic. Wartości czasowesą wyrażone w milisekundach dla 50 000 operacji na słowniku z kluczami i są wartościami całkowi-toliczbowymi wykonywanymi w komputerze PC z procesorem 1,5 GHz. (Różnice między generycz-nymi i niegenerycznymi wersjami wynikają z konieczności stosowania pakowania w jednym przy-padku i występują tylko w odniesieniu do typów wartościowych).
Poleć książkęKup książkę
Słowniki 317
Tabela 7.1. Klasy słownikowe
Typ Strukturawewnętrzna
Indekso-wanie
Narzutpamię-ciowy(średnialiczbabajtów naelement)
Szybkość— losowewstawianie
Szybkość—wstawianiesekwen-cyjne
Szybkość—pobiera-nieelementówwg klucza
Niesortowane
Dictionary <K,V> Tablicaskrótów
Nie 22 30 30 20
Hashtable Tablicaskrótów
Nie 38 50 50 30
ListDictionary Listapowiązana
Nie 36 50 000 50 000 50 000
OrderedDictionary Tablicaskrótów +tablica
Tak 59 70 70 40
Sortowane
SortedDictionary<K,V>
Drzewoczerwono-czarne
Nie 20 130 100 120
SortedList <K,V> Dwie tablice Tak 2 3300 30 40
SortedList Dwie tablice Tak 27 4500 100 180
W notacji wielkiego O czasy pobierania elementów wg klucza wynoszą:
O(1) dla Hashtable, Dictionary oraz OrderedDictionary;
O(log n) dla SortedDictionary i SortedList;
O(n) dla ListDictionary (i typów niesłownikowych, takich jak List<T>).
Parametr n reprezentuje liczbę elementów w kolekcji.
Interfejs IDictionary<TKey,TValue>Interfejs IDictionary<TKey,TValue> to standardowy protokół dla wszystkich kolekcji przechowują-cych pary klucz – wartość. Stanowi on rozszerzenie interfejsu ICollection<T>, do którego dodajemetody i własności umożliwiające dostęp do elementów na podstawie kluczy dowolnego typu:
public interface IDictionary <TKey, TValue> : ICollection <KeyValuePair <TKey, TValue>>, IEnumerable{ bool ContainsKey (TKey key); bool TryGetValue (TKey key, out TValue value); void Add (TKey key, TValue value); bool Remove (TKey key);
Poleć książkęKup książkę
318 Rozdział 7. Kolekcje
TValue this [TKey key] { get; set; } // g ówny indeksator — wg klucza ICollection <TKey> Keys { get; } // zwraca tylko klucze ICollection <TValue> Values { get; } // zwraca tylko warto ci}
W .NET Framework 4.5 dodano interfejs o nazwie IReadOnlyDictionary<TKey,TValue> definiujący podzbiór składowych słownika tylko do odczytu. Odpowiada
on typowi IMapView<K,V> Windows Runtime i został wprowadzony głównie jakojego odpowiednik.
Aby dodać element do słownika, należy wywołać metodę Add albo użyć metody dostępowej indeksu— ta druga dodaje element do słownika, jeśli nie ma w nim jeszcze takiego klucza (a jeśli jest, todokonuje modyfikacji elementu). W żadnej implementacji słownika nie może się powtórzyć ani jedenklucz, więc dwukrotne wywołanie metody Add z takim samym kluczem powoduje wyjątek.
Aby pobrać element ze słownika, należy się posłużyć indeksatorem albo metodą TryGetValue. Jeżelidany klucz nie istnieje, indeksator zgłasza wyjątek, podczas gdy metoda TryGetValue zwraca fałsz.Istnienie elementu w strukturze można sprawdzić za pomocą metody ContainsKey. Jeśli jednakpóźniej dany element trzeba pobrać, będzie to oznaczało konieczność wykonania dwóch takichsamych operacji wyszukiwania.
Operacja enumeracji struktury typu IDictionary<TKey,TValue> zwraca sekwencję struktur KeyValuePair:public struct KeyValuePair <TKey, TValue>{ public TKey Key { get; } public TValue Value { get; }}
Istnieje możliwość przeglądania tylko kluczy lub tylko wartości przy użyciu własności Keys i Values.
W następnej sekcji przedstawiamy przykład użycia tego interfejsu w połączeniu z generyczną klasąDictionary.
Interfejs IDictionaryNiegeneryczny interfejs IDictionary jest bardzo podobny do generycznego IDictionary<TKey,TValue>,ale różni się od niego w dwóch ważnych aspektach. Należy wiedzieć o tych różnicach, ponieważinterfejs IDictionary występuje w starym kodzie (włącznie z samą platformą .NET Framework):
Próba pobrania przez indeksator nieistniejącego klucza kończy się zwróceniem wartości null(a nie wyjątkiem).
Do sprawdzania, czy dany element znajduje się w strukturze, służy metoda Contains, a nieContainsKey.
Efektem przeliczania niegenerycznego IDictionary jest zwrot sekwencji struktur DictionaryEntry:public struct DictionaryEntry{ public object Key { get; set; } public object Value { get; set; }}
Poleć książkęKup książkę
Słowniki 319
Klasy Dictionary<TKey,TValue> i HashtableGeneryczna klasa Dictionary należy do najczęściej używanych kolekcji (obok List<T>). Do przecho-wywania kluczy i wartości wykorzystuje tablicę skrótów (ang. hashtable), dzięki czemu jest szybkai efektywna.
Niegeneryczna wersja klasy Dictionary<TKey,TValue> nazywa się Hashtable. Nieistnieje niegeneryczna klasa o nazwie Dictionary. Dlatego pisząc Dictionary,mamy na myśli generyczną klasę Dictionary<TKey,TValue>.
Klasa Dictionary implementuje zarówno generyczny, jak i niegeneryczny interfejs IDictionary,przy czym generyczna wersja jest udostępniona publicznie. W istocie Dictionary to „podręcznikowa”implementacja generycznego interfejsu IDictionary.
Oto przykład jej użycia:var d = new Dictionary<string, int>();
d.Add("Jeden", 1);d["Dwa"] = 2; // dodaje element do s ownika, poniewa nie ma w nim jeszcze "dwa"d["Dwa"] = 22; // modyfikuje s ownik, poniewa "dwa" ju w nim jestd["Trzy"] = 3;
Console.WriteLine (d["Dwa"]); // drukuje "22"Console.WriteLine (d.ContainsKey ("Jeden")); // prawda (szybka operacja)Console.WriteLine (d.ContainsValue (3)); // prawda (wolna operacja)int val = 0;if (!d.TryGetValue ("jedeN", out val)) Console.WriteLine ("Brak"); // "Brak" (wielko liter ma znaczenie)
// trzy ró ne sposoby przegl dania s ownika:
foreach (KeyValuePair<string, int> kv in d) // Jeden; 1 Console.WriteLine (kv.Key + "; " + kv.Value); // Dwa; 22 // Trzy; 3
foreach (string s in d.Keys) Console.Write (s); // JedenDwaTrzyConsole.WriteLine();foreach (int i in d.Values) Console.Write (i); // 1223
Wewnętrzna tablica skrótów konwertuje klucz każdego elementu na całkowitoliczbową wartośćskrótu, która jest pseudoniepowtarzalna, a następnie za pomocą specjalnego algorytmu konwertujeten skrót na klucz mieszający. Wewnętrznie za pomocą tego klucza wybierany jest „kubełek”, doktórego należy dany wpis. Jeśli kubełek zawiera więcej niż jedną wartość, to jest przeszukiwany algo-rytmem liniowym. Dobra funkcja mieszająca nie dąży do zwracania wyłącznie niepowtarzalnychskrótów (co w większości przypadków byłoby niemożliwe), tylko do równomiernego rozmieszczeniaskrótów w 32-bitowej przestrzeni całkowitoliczbowej. W ten sposób unika się groźby powstaniabardzo małej liczby bardzo dużych (i nieefektywnych) kubełków.
Klucze w słowniku mogą być każdego typu, pod warunkiem że można je porównywać i tworzyćz nich wartości skrótu. Domyślnie klucze porównuje się za pomocą metody klucza object.Equals,a pseudoniepowtarzalna wartość skrótu jest obliczana przez metodę klucza GetHashCode. Możnato zmienić przez przesłonięcie tych metod lub dostarczenie obiektu implementującego interfejs
Poleć książkęKup książkę
320 Rozdział 7. Kolekcje
IEqualityComparer podczas tworzenia słownika. Możliwość tę wykorzystuje się często, gdy stoso-wane są klucze łańcuchowe w celu użycia komparatora nierozróżniającego wielkości liter:
var d = new Dictionary<string, int> (StringComparer.OrdinalIgnoreCase);
Szerzej na ten temat piszemy jeszcze w podrozdziale „Dołączanie protokołów równości i porządko-wania”.
Tak jak w przypadku wszystkich innych typów kolekcji, wydajność słownika można nieco podnieśćprzez określenie w konstruktorze oczekiwanego rozmiaru struktury, co pozwala ograniczyć potrzebęwykonywania operacji zmiany rozmiaru (lub w ogóle jej uniknąć).
Niegeneryczna wersja nazywa się Hashtable i pod względem funkcjonalnym jest podobna do gene-rycznej, tylko udostępnia niegeneryczny interfejs IDictionary, o którym była mowa wcześniej.
Wadą klas Dictionary i Hashtable jest to, że nie sortują przechowywanych elementów. Nie zachowująnawet kolejności dodawania wpisów. Jak wszystkie słowniki, struktury te nie pozwalają na zapisaniedwóch takich samych kluczy.
Gdy w .NET Framework 2.0 wprowadzono generyczne kolekcje, programiści CLRpostanowili nadać im nazwy zgodne z tym, co reprezentują (Dictionary, List), a nieodnoszące się do ich wewnętrznej implementacji (Hashtable, ArrayList). Choćjest to dobra decyzja, dzięki której w przyszłości będzie można bez przeszkód zmieniaćpodstawową implementację, wybrane nazwy nie pozwalają się zorientować, jakąwydajnością (a informacja ta jest często najważniejszym kryterium wyboru) charakte-ryzują się poszczególne kolekcje.
Klasa OrderedDictionaryOrderedDictionary to niegeneryczny słownik przechowujący elementy w kolejności ich dodawania.W tej strukturze elementy dostępne są zarówno wg indeksu, jak i wg klucza.
OrderedDictionary nie jest słownikiem posortowanym.
Klasa OrderedDictionary jest kombinacją klas Hashtable i ArrayList, tzn. zawiera całą funkcjonalnośćpierwszej i kilka dodatkowych funkcji, takich jak RemoveAt i indeksator całkowitoliczbowy. Ponadtostruktura ta udostępnia własności Keys i Values zwracające elementy w pierwotnym porządku.
Klasę tę wprowadzono w .NET 2.0, ale wciąż nie wiadomo dlaczego nie ma jej wersji generycznej.
Klasy ListDictionary i HybridDictionaryKlasa ListDictionary przechowuje dane w liście powiązanej jednostronnie. Nie sortuje elementów,ale zapisuje je w kolejności dodawania. Struktura ta działa bardzo wolno, gdy jest duża. Jedyny sensjej istnienia to wysoka wydajność dla bardzo małych list (zawierających mniej niż dziesięć elementów).
Klasa HybridDictionary to ListDictionary automatycznie konwertująca się na Hashtable po osią-gnięciu określonego rozmiaru w celu uniknięcia problemów wydajnościowych. Chodzi o to, by jak
Poleć książkęKup książkę
Słowniki 321
najoszczędniej operować pamięcią, gdy słownik jest mały, oraz by zachować dobrą wydajność,kiedy się powiększy. Biorąc jednak pod uwagę czas potrzebny na przeprowadzenie konwersji —oraz to, że klasa Dictionary też nie jest zbyt ciężka ani wolna — nikomu nie zaszkodzi użycie słownikaDictionary w zamian.
Obie te klasy występują tylko w wersji niegenerycznej.
Słowniki sortowanePlatforma .NET zawiera dwie klasy słownikowe o wewnętrznej strukturze sprawiającej, że ich zawar-tość jest zawsze posortowana wg klucza:
SortedDictionary<TKey,TValue>,
SortedList<TKey,TValue>1.
(W tej sekcji skracamy zapis <TKey,TValue> do postaci <,>).
Implementacja klasy SortedDictionary<,> bazuje na drzewie czerwono-czarnym — strukturzedanych, która charakteryzuje się taką samą wydajnością w każdej operacji wstawiania i pobieraniaelementu.
Implementację klasy SortedList<,> stanowi uporządkowana para tablic, co zapewnia szybkie pobie-ranie danych (za pomocą binarnego algorytmu wyszukiwania), ale mało efektywne wstawianieelementów (ponieważ trzeba przesunąć istniejące elementy, aby zrobić miejsce dla dodawanego).
Klasa SortedDictionary<,> jest znacznie szybsza od SortedList<,> we wstawianiu elementów w loso-wej kolejności (zwłaszcza gdy struktura danych jest duża). Za to SortedList<,> dodatkowo umożliwiaodnoszenie się do elementów wg indeksu lub wg klucza. Mając posortowaną listę, można bezpo-średnio przejść do n-tego elementu sekwencji (posługując się indeksatorem lub własnościami Keysi Values). Aby zrobić to samo ze strukturą SortedDictionary<,>, należy ręcznie przejrzeć n elemen-tów. (Ewentualnie można napisać klasę łączącą posortowany słownik z listą).
Żadna z tych trzech kolekcji nie pozwala na duplikowanie kluczy (tak jest we wszystkich słownikach).
Poniżej przedstawiamy przykład, w którym za pomocą refleksji ładujemy wszystkie metody zdefinio-wane w klasie System.Object do posortowanej listy, w której klucze stanowią nazwy metod, a następnieprzeglądamy te klucze i ich wartości:
// MethodInfo znajduje si w przestrzeni nazw System.Reflection
var sorted = new SortedList <string, MethodInfo>();
foreach (MethodInfo m in typeof (object).GetMethods()) sorted [m.Name] = m;
foreach (string name in sorted.Keys) Console.WriteLine (name);
foreach (MethodInfo m in sorted.Values) Console.WriteLine (m.Name + " zwraca obiekt typu " + m.ReturnType);
1 stnieje też identyczna pod względem funkcjonalności niegeneryczna wersja o nazwie SortedList.
Poleć książkęKup książkę
322 Rozdział 7. Kolekcje
Oto wynik pierwszego przeglądu:EqualsGetHashCodeGetTypeReferenceEqualsToString
A to jest wynik drugiej pętli:Equals zwraca obiekt typu System.BooleanGetHashCode zwraca obiekt typu System.Int32GetType zwraca obiekt typu System.TypeReferenceEquals zwraca obiekt typu System.BooleanToString zwraca obiekt typu System.String
Zauważ, że zawartość wstawiliśmy do słownika za pomocą indeksatora. Gdybyśmy zamiast niegoużyli metody Add, zgłosiłaby wyjątek, ponieważ klasa object, której dotyczy stosowana przez nas re-fleksja, przeciąża metodę Equals, a do słownika nie można dodać dwa razy takiego samego klucza.Dzięki użyciu indeksatora drugi wpis po prostu zastąpi poprzedni i nie wystąpi żaden błąd.
Jeśli trzeba zapisać kilka elementów pod takim samym kluczem, to elementy wartościmożna zdefiniować jako listy:SortedList <string, List<MethodInfo>>
Wracając do naszego przykładu: poniższa instrukcja pobiera obiekt MethodInfo, którego klucz toGetHashCode. Dokładnie tak samo pracowalibyśmy ze zwykłym słownikiem:
Console.WriteLine (sorted ["GetHashCode"]); // Int32 GetHashCode()
Wszystko, co do tej pory zrobiliśmy, dałoby się wykonać także z klasą SortedDictionary<,>. Aleponiższe dwa wiersze kodu zadziałają tylko z listą posortowaną, ponieważ pobieramy w nich ostatniklucz i ostatnią wartość:
Console.WriteLine (sorted.Keys [sorted.Count - 1]); // ToStringConsole.WriteLine (sorted.Values[sorted.Count - 1].IsVirtual); // prawda
Kolekcje i pośredniki z możliwością dostosowywaniaOpisane w poprzednich podrozdziałach klasy kolekcji są wygodne w użyciu, ponieważ można bezpo-średnio tworzyć ich egzemplarze. Niestety, nie ma możliwości kontrolowania sposobu dodawaniaani usuwania elementów. Możliwość taka jest jednak potrzebna w aplikacjach, w których używanesą ściśle typizowane kolekcje, np.:
aby uruchomić zdarzenie w reakcji na dodanie lub usunięcie elementu;
aby zaktualizować własności z powodu dodania lub usunięcia elementu;
aby wykryć „niedozwoloną” operację dodawania lub usuwania i zgłosić wyjątek (gdy np. operacjałamie jakieś zasady biznesowe).
Platforma .NET Framework zawiera klasy kolekcji przeznaczone do użytku właśnie w takich sytu-acjach. Znajdują się one w przestrzeni nazw System.Collections.ObjectModel i tak naprawdę są
Poleć książkęKup książkę
Kolekcje i pośredniki z możliwością dostosowywania 323
pośrednikami lub opakowaniami implementującymi interfejs IList<T> lub IDictionary<,> przezprzekazywanie metod do podstawowej kolekcji. Każda operacja Add, Remove i Clear zostaje przekiero-wana przez metodę wirtualną, która po przesłonięciu stanowi rodzaj „bramy”.
Klasy kolekcji z możliwością dostosowywania są powszechnie wykorzystywane do tworzenia publicz-nie dostępnych kolekcji, takich jak np. kolekcja kontrolek publicznych klasy System.Windows.Form.
Klasy Collection<T> i CollectionBaseKlasa Collection<T> to modyfikowalne opakowanie klasy List<T>.
Implementuje ona interfejsy IList<T> i IList oraz definiuje cztery dodatkowe metody wirtualnei chronioną własność:
public class Collection<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable{ // ... protected virtual void ClearItems(); protected virtual void InsertItem (int index, T item); protected virtual void RemoveItem (int index); protected virtual void SetItem (int index, T item);
protected IList<T> Items { get; }}
Metody wirtualne stanowią bramę, przez którą można „się podpiąć”, aby zmienić lub rozszerzyćnormalną funkcjonalność listy. Chroniona własność Items umożliwia implementatorowi uzyskaniebezpośredniego dostępu do „wewnętrznej listy” — w ten sposób można dokonywać zmian wewnątrzbez uruchamiania metod wirtualnych.
Metody wirtualne nie muszą być przesłonięte. Można je zostawić nietknięte, aż nadejdzie potrzebamodyfikacji domyślnego działania listy. Poniżej znajduje się schematyczny przykład ilustrującytypowy sposób użycia klasy Collection<T>:
public class Animal{ public string Name; public int Popularity;
public Animal (string name, int popularity) { Name = name; Popularity = popularity; }}
public class AnimalCollection : Collection <Animal>{ // AnimalCollection to ju w pe ni funkcjonalna lista zwierz t. // Nie jest potrzebny aden dodatkowy kod.}
public class Zoo // klasa, która b dzie udost pnia AnimalCollection,{ // normalnie zawiera aby dodatkowe sk adowe public readonly AnimalCollection Animals = new AnimalCollection();}
Poleć książkęKup książkę
324 Rozdział 7. Kolekcje
class Program{ static void Main() { Zoo zoo = new Zoo(); zoo.Animals.Add (new Animal ("Kangur", 10)); zoo.Animals.Add (new Animal ("Król Lew", 20)); foreach (Animal a in zoo.Animals) Console.WriteLine (a.Name); }}
W tej postaci klasa AnimalCollection nie przewyższa funkcjonalnością prostej klasy List<Animal>,ponieważ została stworzona tylko po to, by można ją było w przyszłości rozszerzyć. Dla przykładudo klasy Animal dodamy teraz własność Zoo, aby można było określić, w którym zoo mieszka danezwierzę, i dodatkowo przesłonimy wszystkie metody wirtualne klasy Collection<Animal>, aby za-pewnić automatyczną obsługę tej własności:
public class Animal{ public string Name; public int Popularity; public Zoo Zoo { get; internal set; } public Animal(string name, int popularity) { Name = name; Popularity = popularity; }}
public class AnimalCollection : Collection <Animal>{ Zoo zoo; public AnimalCollection (Zoo zoo) { this.zoo = zoo; } protected override void InsertItem (int index, Animal item) { base.InsertItem (index, item); item.Zoo = zoo; } protected override void SetItem (int index, Animal item) { base.SetItem (index, item); item.Zoo = zoo; } protected override void RemoveItem (int index) { this [index].Zoo = null; base.RemoveItem (index); } protected override void ClearItems() { foreach (Animal a in this) a.Zoo = null; base.ClearItems(); }}
public class Zoo{ public readonly AnimalCollection Animals; public Zoo() { Animals = new AnimalCollection (this); }
Poleć książkęKup książkę
Kolekcje i pośredniki z możliwością dostosowywania 325
Klasa Collection<T> zawiera też konstruktor przyjmujący obiekty implementujące interfejs IList<T>.Jednak inaczej niż jest w przypadku innych klas kolekcji, przekazana lista nie zostanie skopiowana,tylko nowy egzemplarz klasy Collection<T> będzie pośrednikiem do opakowywanej listy, więcwszelkie wprowadzane w niej zmiany będą widoczne przez tego pośrednika (choć bez uruchamianiametod wirtualnych klasy Collection<T>).
Klasa CollectionBase
Klasa CollectionBase to niegeneryczna wersja klasy Collection<T>, którą wprowadzono w wersji1.0 platformy. Zapewnia bardzo podobną funkcjonalność jak Collection<T>, tylko jest mniej wygodnaw użyciu. Zamiast szablonowych metod: InsertItem, RemoveItem, SetItem i ClearItem, klasa CollectionBase zawiera metody „zaczepowe”, które podwajają tylko zestaw potrzebnych metod: OnInsert,
OnInsertComplete, OnSet, OnSetComplete, OnRemove, OnRemoveComplete, OnClear oraz OnClearComplete.Jako że klasa CollectionBase nie jest generyczna, tworząc jej podklasę, należy dodatkowo zaimple-mentować metody typizowane — przynajmniej indeksator i metodę Add.
Klasy KeyedCollection<TKey,TItem> i DictionaryBaseKlasa KeyedCollection<TKey,TItem> jest podklasą klasy Collection<TItem>. W pewnych obszarachrozszerza jej funkcjonalność, a w innych ogranicza. Jeśli chodzi o rozszerzenia, to dodaje możliwośćodnoszenia się do elementów wg klucza, tak jak w słownikach. Likwiduje natomiast możliwośćtworzenia pośredników listy wewnętrznej.
Kolekcja KeyedCollection przypomina w pewnym stopniu klasę OrderedDictionary, ponieważtakże jest kombinacją liniowej listy i tablicy skrótów. Jednak w odróżnieniu od niej nie implementujeinterfejsu IDictionary i nie rozpoznaje pojęcia pary klucz – wartość. Klucze są tworzone z samychelementów przez abstrakcyjną metodę GetKeyForItem. Oznacza to, że kolekcję taką można przeglądaćw taki sam sposób jak zwykłą listę.
Klasę KeyedCollection<TKey,TItem> można traktować jak Collection<TItem> z szybkim wyszukiwa-niem po kluczach.
Jako że jest ona podklasą klasy Collection<>, dziedziczy wszystkie jej składniki z wyjątkiem możli-wości podawania istniejącej listy konstruktorowi. Dodatkowe składowe, jakie definiuje, to:
public abstract class KeyedCollection <TKey, TItem> : Collection <TItem>
// ...
protected abstract TKey GetKeyForItem(TItem item); protected void ChangeItemKey(TItem item, TKey newKey);
// szybkie wyszukiwanie wg klucza to dodatek do wyszukiwania indeksowego public TItem this[TKey key] { get; }
protected IDictionary<TKey, TItem> Dictionary { get; }}
Metodę GetKeyForItem należy przesłonić tak, aby prawidłowo obliczała klucze elementów utworzo-nego obiektu. Metodę ChangeItemKey należy wywołać, jeżeli zmieni się własność przechowującaklucz elementu, aby zaktualizować słownik wewnętrzny. Własność Dictionary zwraca wewnętrzny
Poleć książkęKup książkę
326 Rozdział 7. Kolekcje
słownik wykorzystywany do wyszukiwania, tworzony w chwili dodania pierwszego elementu. W raziepotrzeby można zmienić tę zasadę w konstruktorze tak, aby utworzenie słownika następowałodopiero po przekroczeniu pewnego progu (do tego czasu elementy są wyszukiwane liniowo). Dobrympowodem do tego, by nie określać progu utworzenia słownika, jest to, że może on być przydatnydo utworzenia kolekcji ICollection<> kluczy przy użyciu własności Keys klasy Dictionary.
Klasy KeyedCollection<,> najczęściej używa się do tworzenia kolekcji elementów dostępnych poprzezindeksy i nazwy. W ramach przykładu zaimplementujemy naszą klasę AnimalCollection jakoKeyedCollection<string,Animal>:
public class Animal{ string name; public string Name { get { return name; } set { if (Zoo != null) Zoo.Animals.NotifyNameChange (this, value); name = value; } } public int Popularity; public Zoo Zoo { get; internal set; }
public Animal (string name, int popularity) { Name = name; Popularity = popularity; }}
public class AnimalCollection : KeyedCollection <string, Animal>{ Zoo zoo; public AnimalCollection (Zoo zoo) { this.zoo = zoo; }
internal void NotifyNameChange (Animal a, string newName) { this.ChangeItemKey (a, newName); }
protected override string GetKeyForItem (Animal item) { return item.Name; }
// poni sze metody by yby zaimplementowane, jak w poprzednim przyk adzie protected override void InsertItem (int index, Animal item)... protected override void SetItem (int index, Animal item)... protected override void RemoveItem (int index)... protected override void ClearItems()...}
public class Zoo{ public readonly AnimalCollection Animals; public Zoo() { Animals = new AnimalCollection (this); }}
Poleć książkęKup książkę
Kolekcje i pośredniki z możliwością dostosowywania 327
class Program{ static void Main() { Zoo zoo = new Zoo(); zoo.Animals.Add (new Animal ("Kangur", 10)); zoo.Animals.Add (new Animal ("Król Lew", 20)); Console.WriteLine (zoo.Animals [0].Popularity); // 10 Console.WriteLine (zoo.Animals ["Mr Sea Lion"].Popularity); // 20 zoo.Animals ["Kangaroo"].Name = "Mr Roo"; Console.WriteLine (zoo.Animals ["Mr Roo"].Popularity); // 10 }}
DictionaryBase
DictionaryBase to niegeneryczna wersja klasy KeyedCollection. Jest to stara klasa, którą zbudowanow całkiem odmienny sposób niż nowsze — implementuje interfejs IDictionary i podobnie jakCollectionBase wykorzystuje nieporęczne metody zaczepowe: OnInsert, OnInsertComplete, OnSet,OnSetComplete, OnRemove, OnRemoveComplete, OnClear oraz OnClearComplete (i dodatkowo OnGet).Największą zaletą implementacji słownika IDictionary zamiast stosowania podejścia klasy KeyedCollection jest to, że nie trzeba tworzyć podklasy, aby uzyskać klucze. Ponieważ jednak klasa
DictionaryBase istnieje przede wszystkim po to, by utworzyć jej podklasę, ta zaleta nie ma znaczenia.Ulepszony model klasy KeyedCollection z pewnością powstał dlatego, że klasa ta została napisanakilka lat później, kiedy programiści mogli spojrzeć na nią z pewnej perspektywy. Dlatego też klasęDictionaryBase należy traktować głównie jako środek do zapewnienia zgodności ze starym kodem.
Klasa ReadOnlyCollection<T>Klasa ReadOnlyCollection<T> jest opakowaniem, albo pośrednikiem, zapewniającym widok tylko doodczytu kolekcji. Jest przydatna, gdy klasa ma publicznie udostępnić kolekcję, której nie możnamodyfikować z zewnątrz, a którą można zmieniać wewnętrznie.
Kolekcja tylko do odczytu przyjmuje kolekcję wejściową w konstruktorze, do którego ma stałą refe-rencję. Nie tworzy ona statycznej kopii przekazanej kolekcji, więc wszelkie późniejsze zmiany kolekcjiwejściowej są widoczne przez opakowanie.
W ramach przykładu powiedzmy, że chcemy utworzyć klasę publicznie udostępniającą listę łańcu-chów tylko do odczytu o nazwie Names:
public class Test{ public List<string> Names { get; private set; }}
To dopiero połowa pracy. Choć inne typy nie mogą nic przypisać do własności Names, nadal mogąwywoływać na liście metody Add, Remove i Clear. Rozwiązaniem problemu jest klasa ReadOnlyCollection<T>:public class Test{ List<string> names; public ReadOnlyCollection<string> Names { get; private set; }
Poleć książkęKup książkę
328 Rozdział 7. Kolekcje
public Test() { names = new List<string>(); Names = new ReadOnlyCollection<string> (names); }
public void AddInternally() { names.Add ("test"); }}
Teraz tylko składowe klasy Test mogą zmieniać listę nazw:Test t = new Test();
Console.WriteLine (t.Names.Count); // 0t.AddInternally();Console.WriteLine (t.Names.Count); // 1
t.Names.Add ("test"); // b d kompilacji((IList<string>) t.Names).Add ("test"); // NotSupportedException
Dołączanie protokołów równości i porządkowaniaW podrozdziałach „Sprawdzanie równości” i „Określanie kolejności” w rozdziale 6. opisaliśmy stan-dardowe protokoły platformy .NET umożliwiające porównywanie typów i obliczanie ich skrótów.Typ implementujący te protokoły może prawidłowo funkcjonować w słowniku i liście posortowanejbez żadnego dodatkowego przygotowania. Mówiąc konkretniej:
Typ, dla którego metody Equals i GetHashCode zwracają sensowne wyniki, może być wykorzysty-wany jako klucz w strukturach Dictionary i Hashtable.
Typ implementujący interfejsy IComparable i IComparable<T> może być używany jako klucz wewszystkich sortowanych słownikach i listach.
Domyślna implementacja operacji sprawdzania równości i porównywania typu zazwyczaj odzwier-ciedla jego „naturalne” cechy. Ale programiście nie zawsze zależy na domyślnym znaczeniu tychoperacji. Czasami potrzebny jest np. słownik, w którym klucze są typu string i nie ma znaczeniawielkość liter. Innym razem ktoś może potrzebować listy klientów posortowanej wg kodów poczto-wych. Dlatego na platformie .NET Framework stworzono dodatkowy zestaw protokołów „dołącza-nych” o dwojakim przeznaczeniu:
Dzięki nim można włączać alternatywne sposoby określania równości i kolejności elementów.
Umożliwiają korzystanie ze słowników lub posortowanych kolekcji z typem kluczy, które w swejistocie nie są porównywalne.
Protokoły dołączane obejmują następujące interfejsy:
IEqualityComparer i IEqualityComparer<T>
Odpowiada za sprawdzanie równości i obliczanie skrótów.
Rozpoznawany przez Hashtable i Dictionary.
Poleć książkęKup książkę
Dołączanie protokołów równości i porządkowania 329
IComparer i IComparer<T>
Odpowiada za porównywanie pod względem kolejności.
Rozpoznawany przez słowniki i kolekcje posortowane; także Array.Sort.
Każdy interfejs występuje w wersji generycznej i niegenerycznej. Dodatkowo interfejsy IEqualityComparer mają domyślną implementację w klasie o nazwie EqualityComparer.
Ponadto w .NET Framework 4.0 dodano dwa nowe interfejsy: IStructuralEquatable i IStructuralComparable, które umożliwiają wykonywanie porównań strukturalnych na klasach i tablicach.
IEqualityComparer i EqualityComparerInterfejs IEqualityComparer włącza niestandardowe operacje sprawdzania równości i obliczaniaskrótów i jest przeznaczony głównie do pracy z klasami Dictionary i Hashtable.
Przypomnimy pokrótce wymagania, jakie powinien spełniać słownik skrótów. Dla każdego kluczamusi odpowiadać na dwa pytania:
Czy jest taki sam jak inny?
Jaka jest jego całkowitoliczbowa wartość skrótu?
Komparator sprawdzający równość odpowiada na te pytania przez implementację interfejsówIEqualityComparer:
public interface IEqualityComparer<T>{ bool Equals (T x, T y); int GetHashCode (T obj);}
public interface IEqualityComparer // wersja niegeneryczna{ bool Equals (object x, object y); int GetHashCode (object obj);}
Aby napisać własny komparator, należy zaimplementować jeden z tych interfejsów lub oba (imple-mentacja obu zapewnia największą elastyczność). Ponieważ jednak jest to dość czasochłonne zajęcie,ewentualnie można też utworzyć podklasę abstrakcyjnej klasy EqualityComparer, której definicjawygląda następująco:
public abstract class EqualityComparer<T> : IEqualityComparer, IEqualityComparer<T>{ public abstract bool Equals (T x, T y); public abstract int GetHashCode (T obj);
bool IEqualityComparer.Equals (object x, object y); int IEqualityComparer.GetHashCode (object obj);
public static EqualityComparer<T> Default { get; }}
Klasa EqualityComparer implementuje oba interfejsy, więc programiście pozostaje już tylko prze-słonięcie dwóch abstrakcyjnych metod.
Poleć książkęKup książkę
330 Rozdział 7. Kolekcje
Semantyka metod Equals i GetHashCode jest taka sama jak metod object.Equals i object.GetHashCodeopisanych w rozdziale 6. W poniższym przykładzie definiujemy klasę Customer z dwoma polamii piszemy komparator porównujący imiona i nazwiska:
public class Customer{ public string LastName; public string FirstName;
public Customer (string last, string first) { LastName = last; FirstName = first; }}public class LastFirstEqComparer : EqualityComparer <Customer>{ public override bool Equals (Customer x, Customer y) => x.LastName == y.LastName && x.FirstName == y.FirstName;
public override int GetHashCode (Customer obj) => (obj.LastName + ";" + obj.FirstName).GetHashCode();}
Aby pokazać, jak to działa, utworzymy dwóch klientów:Customer c1 = new Customer ("Bara ski", "Jan");Customer c2 = new Customer ("Bara ski", "Jan");
Jako że nie przesłoniliśmy metody object.Equals, zastosowanie ma normalna semantyka refe-rencyjna:
Console.WriteLine (c1 == c2); // fa szConsole.WriteLine (c1.Equals (c2)); // fa sz
To samo dzieje się, gdy użyjemy naszych obiektów w słowniku, nie określając własnego komparatora:var d = new Dictionary<Customer, string>();d [c1] = "Jan";Console.WriteLine (d.ContainsKey (c2)); // fa sz
A teraz podajemy własny komparator:var eqComparer = new LastFirstEqComparer();var d = new Dictionary<Customer, string> (eqComparer);d [c1] = "Jan";Console.WriteLine (d.ContainsKey (c2)); // prawda
W tym przypadku musielibyśmy uważać, aby nie zmienić pól FirstName ani LastName klienta pod-czas używania obiektu w słowniku. W przeciwnym razie zmieniłaby się wartość skrótu i słownikprzestałby działać.
Metoda EqualityComparer<T>.DefaultMetoda EqualityComparer<T>.Default zwraca ogólny komparator, którego można używać zamiaststatycznej metody object.Equals. Jej zaletą jest to, że najpierw sprawdza, czy typ T implementujeinterfejs IEquatable<T>, i jeśli tak, to wywołuje tamtą implementację, pozwalając uniknąć pakowania.Jest to szczególnie przydatne w metodach generycznych:
Poleć książkęKup książkę
Dołączanie protokołów równości i porządkowania 331
static bool Foo<T> (T x, T y){ bool same = EqualityComparer<T>.Default.Equals (x, y); ...
IComparer i ComparerKomparatory umożliwiają dołączanie do posortowanych słowników i kolekcji niestandardowej logikiporównawczej.
Dla nieposortowanego słownika, np. Dictionary i Hashtable, komparator jest bezużyteczny — w ta-kim przypadku potrzebny jest IEqualityComparer, aby możliwe było obliczanie wartości skrótów.Analogicznie komparator równości jest nieprzydatny dla posortowanych słowników i kolekcji.
Oto definicje interfejsu IComparer:public interface IComparer{ int Compare(object x, object y);}public interface IComparer <in T>{ int Compare(T x, T y);}
Tak jak w przypadku komparatorów równości, istnieje klasa abstrakcyjna, którą można rozszerzyćzamiast pisać implementację interfejsów:
public abstract class Comparer<T> : IComparer, IComparer<T>{ public static Comparer<T> Default { get; }
public abstract int Compare (T x, T y); // do implementacji przez programist int IComparer.Compare (object x, object y); // do implementacji przez programist}
Poniżej znajduje się przykład ilustrujący klasę opisującą życzenia i komparator sortujący życzenia wgważności:
class Wish{ public string Name; public int Priority;
public Wish (string name, int priority) { Name = name; Priority = priority; }}
class PriorityComparer : Comparer <Wish>{ public override int Compare (Wish x, Wish y) { if (object.Equals (x, y)) return 0; // test bezpiecze stwa return x.Priority.CompareTo (y.Priority); }}
Poleć książkęKup książkę
332 Rozdział 7. Kolekcje
Test bezpieczeństwa metody object.Equals gwarantuje nam, że nigdy nie zaprzeczymy metodzieEquals. Wywołanie statycznej metody object.Equals jest w tym przypadku lepszym rozwiązaniemniż wywołanie x.Equals, ponieważ metoda ta zadziała także, gdy x będzie null!
Poniżej przedstawiamy przykład użycia naszego komparatora PriorityComparer do posortowanialisty:
var wishList = new List<Wish>();wishList.Add (new Wish ("Pokój", 2));wishList.Add (new Wish ("Bogactwo", 3));wishList.Add (new Wish ("Mi o ", 2));wishList.Add (new Wish ("3 kolejne yczenia", 1));
wishList.Sort (new PriorityComparer());foreach (Wish w in wishList) Console.Write (w.Name + " | ");
// WYNIK: 3 kolejne yczenia | Bogactwo | Mi o | Pokój |
W następnym przykładzie klasa SurnameComparer pozwala na posortowanie nazwisk w kolejnościodpowiedniej dla książki telefonicznej:
class SurnameComparer : Comparer <string>{ string Normalize (string s) { s = s.Trim().ToUpper(); if (s.StartsWith ("MC")) s = "MAC" + s.Substring (2); return s; }
public override int Compare (string x, string y) => Normalize (x).CompareTo (Normalize (y));}
Oto przykład użycia tego komparatora w posortowanym słowniku:var dic = new SortedDictionary<string,string> (new SurnameComparer());dic.Add ("MacPhail", "drugi!");dic.Add ("MacWilliam", "trzeci!");dic.Add ("McDonald", "pierwszy!");
foreach (string s in dic.Values) Console.Write (s + " "); // pierwszy! drugi! trzeci!
Klasa StringComparerStringComparer to gotowa klasa do sprawdzania równości i porównywania łańcuchów, która dodat-kowo umożliwia określenie języka i podjęcie decyzji, czy ma być rozpoznawana wielkość liter.Klasa ta implementuje interfejsy IEqualityComparer i IComparer (oraz ich generyczne wersje), więcmożna jej używać z każdym typem słownika lub posortowanej kolekcji:
// CultureInfo znajduje si w przestrzeni nazw System.Globalization
public abstract class StringComparer : IComparer, IComparer <string>, IEqualityComparer, IEqualityComparer <string>{
Poleć książkęKup książkę
Dołączanie protokołów równości i porządkowania 333
public abstract int Compare (string x, string y); public abstract bool Equals (string x, string y); public abstract int GetHashCode (string obj);
public static StringComparer Create (CultureInfo culture, bool ignoreCase); public static StringComparer CurrentCulture { get; } public static StringComparer CurrentCultureIgnoreCase { get; } public static StringComparer InvariantCulture { get; } public static StringComparer InvariantCultureIgnoreCase { get; } public static StringComparer Ordinal { get; } public static StringComparer OrdinalIgnoreCase { get; }}
Klasa StringComparer jest abstrakcyjna, więc egzemplarze otrzymuje się przez metody statyczne i wła-sności. Metoda StringComparer.Ordinal odzwierciedla domyślny sposób sprawdzania równości łań-cuchów, a metoda StringComparer.CurrentCulture dotyczy porównywania pod względem kolejności.
W poniższym przykładzie tworzymy porządkowy słownik nierozróżniający wielkości liter, taki żedict["Jan"] i dict["JAN"] znaczą to samo:
var dict = new Dictionary<string, int> (StringComparer.OrdinalIgnoreCase);
W następnym przykładzie sortujemy tablicę imion wg zasad australijskiej odmiany angielskiego:string[] names = { "Tom", "HARRY", "sheila" };CultureInfo ci = new CultureInfo ("en-AU");Array.Sort<string> (names, StringComparer.Create (ci, false));
Ostatni przykład to rozpoznająca kultury wersja komparatora SurnameComparer, który napisaliśmyw poprzedniej sekcji (do porównywania nazwisk w sposób odpowiedni dla książki telefonicznej):
class SurnameComparer : Comparer <string>{ StringComparer strCmp; public SurnameComparer (CultureInfo ci) { // utworzenie rozpoznaj cego wielko liter i kultury komparatora a cuchów strCmp = StringComparer.Create (ci, false); } string Normalize (string s) { s = s.Trim(); if (s.ToUpper().StartsWith ("MC")) s = "MAC" + s.Substring (2); return s; }
public override int Compare (string x, string y) { // bezpo rednie wywo anie metody Compare na naszym komparatorze StringComparer return strCmp.Compare (Normalize (x), Normalize (y)); }}
Interfejsy IStructuralEquatable i IStructuralComparableJak napisaliśmy w poprzednim rozdziale, struktury domyślnie implementują porównywanie struktu-ralne, które polega na tym, że dwie struktury zostają uznane za równe, jeśli wszystkie ich pola sąsobie równe. Czasami jednak strukturalne porównywanie i równość są przydatne także w innych
Poleć książkęKup książkę
334 Rozdział 7. Kolekcje
typach, np. tablicach i krotkach, do których można je dodać jako protokoły dołączane. W wersji 4.0platformy wprowadzono więc dwa nowe interfejsy:
public interface IStructuralEquatable{ bool Equals (object other, IEqualityComparer comparer); int GetHashCode (IEqualityComparer comparer);}
public interface IStructuralComparable{ int CompareTo (object other, IComparer comparer);}
Przekazywane komparatory IEqualityComparer i IComparer są stosowane do każdego elementuw obiekcie złożonym. Możemy to zademonstrować przy użyciu tablic i krotek, które implementująte interfejsy. W poniższym przykładzie sprawdzamy, czy dwie tablice są sobie równe, najpierw za po-mocą domyślnej metody Equals, a następnie przy użyciu jej wersji z interfejsu IStructuralEquatable:
int[] a1 = { 1, 2, 3 };int[] a2 = { 1, 2, 3 };IStructuralEquatable se1 = a1;Console.Write (a1.Equals (a2)); // fa szConsole.Write (se1.Equals (a2, EqualityComparer<int>.Default)); // prawda
Oto kolejny przykład:string[] a1 = "gdyby kózka nie skaka a".Split();string[] a2 = "GDYBY KÓZKA NIE SKAKA A".Split();IStructuralEquatable se1 = a1;bool isTrue = se1.Equals (a2, StringComparer.InvariantCultureIgnoreCase);
Krotki działają tak samo:var t1 = Tuple.Create (1, "foo");var t2 = Tuple.Create (1, "FOO");IStructuralEquatable se1 = t1;bool isTrue = se1.Equals (t2, StringComparer.InvariantCultureIgnoreCase);IStructuralComparable sc1 = t1;int zero = sc1.CompareTo (t2, StringComparer.InvariantCultureIgnoreCase);
Różnica, jeśli chodzi o krotki, jest taka, że ich domyślne implementacje operacji sprawdzania równościi porównywania mają charakter strukturalny:
var t1 = Tuple.Create (1, "FOO");var t2 = Tuple.Create (1, "FOO");Console.WriteLine (t1.Equals (t2)); // prawda
Poleć książkęKup książkę
1041
Skorowidz
.ASMX Web Services, 217
.NET Framework, 205
Aabstrakcyjne
klasy, 105składowe, 105
ACL, Access Control List, 861adapter
StringReader, 632StringWriter, 632strumienia, 626
adapterybinarne, 626, 632tekstowe, 626, 627XML, 627
adnotacje, 458ADO.NET, 214adres
IPv4, 664IPv6, 664SMTP, 691URI, 665
agregacje bez ziarna, 428akcesory widoku, 652aksjomaty metody object.Equals,
279aktualizowanie danych, 446aktywacja typów, 774algorytm
MD5, 866porównywania kulturowego,
225porównywania
porządkowego, 225
SHA, 866SHA256, 866SHA384, 866
algorytmy szyfrowania, 874alias extern, 83aliasy typów, 83alternatywy, 1011analiza
działających procesów, 539poleceń, 1018wątków w procesie, 539wyrażeń, 1018
anonimowe wywoływanieskładowych, 790, 831
anulowanie zadań, 942anulowanie zapytania PLINQ,
927API EF, 381API COM, 987API L2S, 381aplikacje
typu WPF, 564Windows Store, 775
APM, AsynchronousProgramming Model, 606
architekturadomeny aplikacji, 959Roslyn, 1014sieci, 661strumienia, 611
archiwum ZIP, 636argument, 28
NumberStyles, 253argumenty
metody GroupJoin, 406metody Join, 406
nazwane, 24, 64, 987typów, 126
ASCII, 229asercja, 515, 522, 529, 858
o zerowej długości, 999, 1010asocjacje, 375ASP.NET, 212ASP.NET 5, 19asynchroniczne wyrażenia
lambda, 593asynchroniczność, 209, 551, 577,
594atak słownikowy, 866atomowość, 882atrapy, 673atrybut, 191, 210, 793
[ComVisible(false)], 991[Conditional], 513, 514[ContractVerification], 537[DataMember], 706[NonSerialized], 720, 722[OnDeserialized], 716, 721[OnDeserializing], 716, 721[OnSerialized], 722[OnSerializing], 716, 722[OptionalField], 723[SecurityTransparent], 847,
848[Serializable], 717[SuppressUnmanagedSecurity],
853[SupressMessage], 537[ThreadStatic], 909APTCA, 847AttributeUsage, 795
Poleć książkęKup książkę
1042 Skorowidz
atrybutFlags, 122LoaderOptimization, 963
atrybutybitmapowe, 794debuggera, 538informacji wywołującego,
193kompresji, 639nazwane, 192niestandardowe, 794podzespołu, 739pozycyjne, 192pseudoniestandardowe, 795serializacji binarnej, 720szyfrowania, 639warunkowe, 198
automatyczna konkatenacjawęzłów XText, 449
automatyczne usuwanienieużytków, 491
awarie, 532
Bbariera, 906bariera wątku wykonawczego,
905bezpieczeństwo, 210, 839
deklaratywne, 843dostępu kodu, 840imperatywne, 843pliku, 640typów, 18, 123wątków, 528, 558, 886–890
bezpieczne metody krytyczne,850
bezpośrednie osadzaniezasobów, 755
białe znaki, 1023biblioteka, 29
PCL, 19PFX, 918
bibliotekiAPTCA, 852DLL, 973natywne, 973WinRT, 21
binarny rewriter, 520, 521BitTorrent, 692blok
catch, 158finally, 158, 161instrukcji, 28, 33kodu, 27try, 158try-catch-finally, 561try-finally, 486
blokady, 881, 886odczytu i zapisu, 893z możliwością uaktualnienia,
895z podwójnym
zatwierdzeniem, 907bloki try-catch-finally, 169blokowanie, 882
bez wykluczania, 878, 892pętlowe, 919wykluczające, 878
błędyparsowania, 255zaokrąglania liczb
rzeczywistych, 49BMP, Basic Multilingual Plane,
231budowanie wyrażeń zapytań, 381buforowanie, 508bufory o stałym rozmiarze, 196
CCAS, code access security, 840CCW, COM-callable wrapper, 991cele
atrybutów, 192delegatów, 142emisji, 816
certyfikat, 749witryny, 872
ciasteczka, Patrz cookiesciąg tekstowy zapytania, 680CLR, 19, 207, 501
implementacjaindeksatorów, 96
implementacjawłasności, 95
COM, Component ObjectModel, 21, 985
COM+, 216cookies, 682cyfrowy certyfikat witryny, 872czas
bieżący, 236działania programu, 18kompilacji, 18letni, 243UTC, 244
czekanie na zadania, 942czystość funkcyjna, 926czyszczenie egzemplarzy
nasłuchujących, 518
Ddane
statyczne, 132uwierzytelniające, 676
data i godzina, 232deasembler, 819debugger, 538
atrybuty, 538punkty kontrolne, 538
debugowanie, 515definicja równości, 277definiowanie
metod generycznych, 814przestrzeni nazw, 455treści, 438typów, 34typów generycznych, 815własnych atrybutów, 796
deklaracje, 450XML, 452
deklarowanieparametrów typów, 128, 135wielu pól naraz, 88
dekoratory strumieni, 612, 626delegat, 18, 139, 382
Action, 143Func, 143MatchEvaluator, 1004
delegatyasynchroniczne, 607multiemisji, 141zgodność, 145
Poleć książkęKup książkę
Skorowidz 1043
deserializacja, 699deszyfrowanie wiadomości, 872diagnostyka, 209, 511diagnozowanie wycieku pamięci,
506diagram UML, 355DLL, Dynamic Link Libraries,
985DLR, dynamiczny system
wykonawczy języka, 825DNS, Domain Name Service,
663, 690dokumentacja XML, 200dokumenty, 450dołączane komparatory, 281dołączanie debuggera, 538DOM, 433domeny aplikacji, 211, 959
architektura, 959likwidowanie, 961monitorowanie, 965tworzenie, 961używanie, 962
domyślnainicjalizacja elementów, 54wartość generyczna, 129
domyślneprzestrzenie nazw, 456ustawienia przezroczystości,
852dostawca
formatu, 245–247WordyFormatProvider, 250
dostęp do składowychniepublicznych, 788
dostępność symbolu, 1034dostosowanie kolekcji, 714drobiazgi, 1023
niestrukturalne, 1025strukturalne, 1025
drzewoskładni Roslyn, 1015wyrażeń, 25 154, 362, 382,
386wywołań, 579wywołań asynchronicznych,
591X-DOM, 435
dynamiczna kontrola typów, 111dynamiczne
wybieranie przeciążonychskładowych, 828
wywoływanie składowej, 786dynamiczny
odbiorca, 188system wykonawczy języka,
825dyrektywa preprocesora, 198,
1024#else, 512, 1024#if, 511, 1024#if LOGGINGMODE, 514#line, 1024fixed, 981using, 80, 82using static, 80
działaniemodelu transparentności,
849programu, 860wyliczeń, 269zdarzeń, 148
dziedziczenie, 101, 107dzielenie
całkowitoliczbowe, 45danych między domenami,
967łańcuchów, 223na części, 930przy użyciu skrótów, 929tekstu, 1003zakresowe, 930
dziennik zdarzeńmonitorowanie, 543odczyt danych, 543Windows, 542zapis danych, 542
EEAP, Event-based
Asynchronous Pattern, 607efektywność wykorzystania
pamięci, 40egzekwowanie
kontraktów, 534
egzemplarz, 35nasłuchujący, 518referencyjny, 39
elementy, 53formatowania, 224główne, 492, 493opcjonalne, 470podklasy kolekcji, 714, 734puste, 470składowe, 710, 711
eliminowanie pustychelementów, 461
emisja podzespołu, 1031emitowanie
generycznych typów, 814klas, 814konstruktorów, 812metod, 809podzespołów i typów, 805pól, 811składowych typów, 809właściwości, 811
encja, 468Entity Framework, 368enumerator, 166
Ffabryka abstrakcyjna, 948FIFO, first-in, first-out, 312filtr, 377
wyjątków, 23, 161filtrowanie, 391
z indeksowaniem, 392finalizatory, 29, 99, 493
wskrzeszanie, 496wywoływanie metody
Dispose(), 495flagi parsowania, 250, 254forma daty
długa, 238krótka, 238
format XML, 208formater, 702
SOAP, 722XML, 705
formatery binarne, 706
Poleć książkęKup książkę
1044 Skorowidz
formatowanie, 244daty i godziny, 254, 255wyliczeń, 257złożone, 248
formularz, 681fragmentacja, 501FTP, File Transfer Protocol, 663,
688funkcja, 18
CreateFileMapping, 979GetComplexMessageHeaders,
513funkcje
asynchroniczne, 582, 589klasy FileStream, 621operatorowe, 177wyrażeniowe, 23
GGAC, Global Assembly Cache,
751, 753generator
liczb losowych, 266list z list, 343
generowaniedynamicznego kodu, 799IL, 799jednostek, 375metod instancji, 810zmiennych lokalnych, 802
generycznekolekcje, 314typy delegacyjne, 143
globalizacja, 261globalny bufor zestawów, 22głębokie klonowanie, 439główne moduły współpracujące,
990granica słowa, 1001granice tablic, 57grupowanie, 416
sekwencji, 390według wielu kluczy, 419
Hhermetyzacja, 17hierarchie obiektów, 396
HTTP, Hypertext TransferProtocol, 663
ciąg tekstowy zapytania, 680cookies, 682dane formularza, 681nagłówki, 680tworzenie serwera, 685
IIANA, Internet Assigned
Numbers Authority, 230identyfikatory, 30IIS, Internet Information
Services, 663IL, Intermediate Language, 20,
737implementowanie
indeksatora, 96interfejsów IComparable, 283interfejsów przeliczeniowych,
293obiektów dynamicznych, 833własności w CLR, 95
implikacje przekazywania przezreferencję, 63
indeksatory, 29, 95, 988indeksowanie tablic, 302inferencja typów literałów
liczbowych, 43informacje
o operatorach zapytań, 388o postępie, 600o woluminie, 646o wskaźnikach, 194
inicjalizacjaelementów, 54pól, 88, 108tablic, 56
inicjalizatoryindeksów, 23kolekcji, 167obiektów, 25, 91, 92, 360własności, 23, 94
initialization vector, IV, 868instalacja
certyfikatu, 749typów, 778
instrukcjabreak, 77, 936continue, 78fixed, 195goto, 78if, 73lock, 879return, 78, 168switch, 74, 823throw, 78try, 158using, 162, 486yield break, 169
instrukcjedeklaracji, 71iteracyjne, 75skoku, 77wyboru, 73wyrażeniowe, 72
integracja z debuggerem, 538interakcja między
subskrybentami., 147interfejs, 17, 116
COM, 985Comparer, 331ICollection, 296, 297ICollection<T>, 297IComparable, 281–283IComparer, 331IConvertible, 258ICustomFormatter, 249IDictionary, 316, 318IDictionary<TKey,TValue>,
317IDispatch, 986IDisposable, 292, 485, 489IEnumerable, 290IEnumerable<T>, 291, 292IEnumerator, 290IEnumerator<T>, 291, 295IEqualityComparer, 320, 328IEqualityComparer<T>, 328IEquatable<T>, 276, 280IFormatProvider, 249IList, 296, 298IList<T>, 298IOrderedEnumerable, 415IOrderedQueryable, 415
Poleć książkęKup książkę
Skorowidz 1045
interfejsIPermission, 841IProducerConsumer
Collection<T>, 952IProgress<T>, 601IQueryable<T>, 362IReadOnlyList<T>, 299ISerializable, 724IStructuralComparable, 333IStructuralEquatable, 273,
333IUnknown, 986IXmlSerializable, 478, 702,
718, 734Progress<T>, 601
interfejsy, 116jawna implementacja, 117konwersja struktury, 120niegeneryczne, 292przeliczeniowe, 293reimplementacja, 118rozszerzanie, 117stosowanie, 120tworzenie, 120wirtualna implementacja
składowych, 118interoperacyjność macierzysta,
211interpolacja łańcuchów, 23, 53IP, Internet Protocol, 663iteratory, 168
komponowanie sekwencji,170
izolacjadomeny, 654podzespołu, 654typów i zestawów, 969
Jjawna implementacja interfejsu,
117jawne określanie typów, 154jednoczesne przetwarzanie
żądań, 551jednolitość typów, 266jednolity system typów, 17jednostka, entity, 369
językpośredni IL, 20XSLT, 483
językidynamiczne, 836zarządzane, 20
JIT, just-in-time, 20
Kkatalog, 648
bazowy aplikacji, 619specjalny, 644
kategoryzacja znaków, 221, 1009klamry, 73klasa, 17, 29, 87
Aes, 868AggregateException, 948, 949AppContext, 287AppDomain, 970Array, 300, 304ArrayList, 308Assembly, 741, 742, 767AssemblyName, 746AutoResetEvent, 897BackgroundWorker, 608Barrier, 905BinaryReader, 632BinaryWriter, 632BitArray, 314BitConverter, 261BlockingCollection, 955BlockingCollection<T>, 954CodeAccessPermission, 840Collection<T>, 323CollectionBase, 325ConcurrentBag<T>, 953Console, 284Contacts, 478Contract, 521Convert, 258CountdownEvent, 901CryptoStream, 868, 869CSharpCompilationOptions,
1030CSharpSyntaxRewriter, 1029CSharpSyntaxWalker, 1022DataContext, 371
DataContractSerializer, 704,709
DataLoadOptions, 377Debug, 515DelegatingHandler, 674Dictionary<TKey,TValue>,
319DictionaryBase, 327Directory, 641DirectoryInfo, 642Dns, 690DynamicMethod, 799DynamicObject, 833, 834Encoding, 230, 631Enumerable, 412Environment, 285Excel.Application, 987ExpandoObject, 836File, 619, 638FileInfo, 642FileIOPermission, 840FileStream, 841FileSystemWatcher, 647HashSet<T>, 314Hashtable, 319HttpClient, 670, 676HttpClientHandler, 675HttpContent, 672HttpListener, 686HttpMessageHandler, 673HybridDictionary, 320IPAddress, 664KeyedCollection<TKey,
TItem>, 325LambdaExpression, 384Lazy<T>, 907LazyInitializer, 908LinkedList<T>, 310List<T>, 308ListDictionary, 320ManualResetEvent, 900Math, 262Mutex, 885NetDataContractSerializer,
704, 709object, 112, 274ObjectContext, 371OpCodes, 820
Poleć książkęKup książkę
1046 Skorowidz
klasaOrderedDictionary, 320Parallel, 919, 933ParallelLoopState, 936Path, 642PermissionSet, 842PrincipalPermission, 840Process, 286Publisher, 751Queue, 312Queue<T>, 312Random, 265ReaderWriterLockSlim, 893,
895ReadOnlyCollection<T>, 327RSA, 873RSACryptoServiceProvider,
875SemaphoreSlim, 892SerializationInfo, 725SharedMem, 982SmtpClient, 691SortedDictionary<,>, 321SortedList<,>, 321SortedSet<T>, 314Stack, 313Stack<T>, 313StackFrame, 540StackTrace, 540Stopwatch, 549StorageFile podstawowa, 649StorageFolder, 648Stream, 613StreamReader, 629StreamWriter, 629StringBuilder, 228StringComparer, 332Supplier, 478SurnameComparer, 332SymbolInfo, 1034SyntaxNode, 1015SyntaxTree, 1019System.Exception, 164Task, 569TaskCompletionSource, 575,
577TaskFactory, 948TextReader, 627, 630
TextWriter, 627, 630ThreadLocal<T>, 909, 910,
925TimeZone, 240TimeZoneInfo, 240Trace, 515TraceListener, 516Type, 777TypeInfo, 775, 1035WebClient, 667, 681WebRequest, 669WebResponse, 669XDocument, 450, 451XElement, 479, 480XmlConvert, 245, 259XmlReader, 465, 469, 479
odczytywanie elementów,469
przedrostki, 473przestrzenie nazw, 473sprawdzanie poprawności,
481wczytywanie atrybutów,
472wczytywanie węzłów, 467zastosowania, 476
XmlReaderSettings, 466XmlSerializer, 730XmlWriter, 474, 480
przedrostki, 476przestrzenie nazw, 476wpisywanie atrybutów, 475wpisywanie węzłów, 475zastosowania, 476
ZipArchive, 636ZipFile, 637abstrakcyjne, 105atrybutów, 191bazowe, 108dziedziczenie, 101jednostek Entity Framework,
370jednostek LINQ to SQL, 369metod egzemplarza, 637monitorowania, 515po stronie klienta, 667pochodne, 101pomocnicze, 284
statyczne, 36, 98, 637tworzenie, 120
klauzulacatch, 160else, 73from, 344inicjalizacji, 76into, 410iteracyjna, 76select, 396warunkowa, 76
klient, 552P2P, 662
klientybogate, 212ubogie, 212
klonowanie głębokie, 439klucz, 319
prywatny, 871publiczny, 743, 871
kodIL, 737, 799, 819niebezpieczny, 195niezarządzany, 977programu hosta, 856transparentny, 851zarządzany, 20
kodowanieASCII, 229, 630base64, 259Unicode, 229UTF-16, 231, 631UTF-8, 630
kolejka, 312FIFO, 312komunikatów, 565LIFO, 109typu producent-konsument,
954kolejność elementów, 470, 923
składowych, 711XML, 729inicjalizacji pól, 90, 98, 108wykonywania działań, 67
kolekcja, 208, 289, 322, 713blokująca, 954pokoleniowa, 499współbieżna, 951
Poleć książkęKup książkę
Skorowidz 1047
kombinacje zapytań, 366komentarz, 27, 33
dokumentacyjny, 200komparator, 331, 415
równości, 331, 419kompilacja, 18, 29
warunkowa, 511, 512kompilator
csc.exe, 29JIT, 20, 95Roslyn, 1013
kompilowanie drzew wyrażeń,382
komponentybibliotek PFX, 918COM, 986
komponowanie sekwencji, 170kompozycja podzapytania, 355kompresja
plików, 636strumienia, 634w pamięci, 636
komunikatyodpowiedzi, 672żądania, 672
konfiguracja Release, 535konflikt nazw, 32konkatenacja
łańcuchów, 52węzłów XText, 449
konsola MMC, 544konstrukcja
funkcyjna, 438try-catch, 561try-catch-finally, 561
konstrukcjegrupujące, 1010sygnalizacyjne, 901
konstruktor bezparametrowy,108
konstruktory, 29, 35, 107egzemplarzy, 89niejawne bez parametrów,
90niepubliczne, 91przeciążanie, 90statyczne, 97
kontekst synchronizacji, 566konteksty typizowane, 372kontrakty, 531
danych, 713kodu, 518, 521
binarny rewriter, 521czystość, 522kompilacja, 521warunki początkowe, 523
sprawdzenie statyczne, 536w konfiguracji Release, 535
kontrawariancja, 136, 145Kontrola konta użytkownika,
UAC, 860kontrola typów
dynamiczna, 111statyczna, 111
kontynuacje, 573, 579, 902na jednym przodku, 947warunkowe, 945z wieloma przodkami, 947zapytania, 358, 410
konwersje, 37dynamiczne, 187, 259dziesiętne, 45jawne, 37jawne niestandardowe, 178liczb rzeczywistych, 258liczbowe, 263między typami
całkowitoliczbowymi, 44między typami
zmiennoprzecinkowymi, 44na format base64, 259niejawne, 37niejawne niestandardowe,
178referencji, 102, 146rozpakowania, 422tablic, 307typu logicznego, 49uchwytów oczekiwania, 903wyliczeń, 121, 267
na łańcuch, 268na typy całkowitoliczbowe,
267z liczb całkowitych, 268
znaków, 52
konwertery typów, 245, 260kopiowanie
płytkie, 302, 307tablicy, 302
kotwice, 1000kowariancja, 133, 146krotki, tuples, 269
porównywanie, 270kryptografia, 864kultura niezmienna, 254kultury, 762kwalifikatory aliasów, 84kwantyfikator, 390, 429, 998,
1009*, 998leniwy, 999zachłanny, 999
LLAN, Local Area Network, 663leksykon języka wyrażeń
regularnych, 1008leniwa inicjalizacja, 906liczby, 262
klasa Math, 262klasa Random, 265struktura BigInteger, 264struktura Complex, 264
licznik wydajności, 544odczyt danych, 546tworzenie, 547wyświetlanie, 545zapis danych, 547
LIFO, last in, first out, 109, 313likwidacja
domen aplikacji, 961obiektów szyfrowania, 870uchwytów oczekiwania, 899
LINQ, Language IntegratedQuery, 25, 208, 335
operatory, 387LINQ to SQL, 368LINQ to XML, 433
DOM, 434lista, 297, 308
kontroli dostępu, ACL, 861
Poleć książkęKup książkę
1048 Skorowidz
literały, 32całkowitoliczbowe, 42reprezentujące liczby
rzeczywiste, 43lokalizacja, 261
Łłańcuch
formatu, 53, 238, 246null, 221
łańcuchowe wywoływanie metod,181
łańcuchydzielenie, 223formatowania daty i godziny,
254, 255formatowania wyliczeń, 257formatowanie, 244klasa StringBuilder, 228kodowanie tekstu, 229łączenie, 223łączenie dekoratorów, 351łączenie operatorów zapytań,
337mechanizmy konwersji, 257metoda string.Format, 224metody statyczne, 221modyfikowanie, 223niestandardowe formatu, 250niestandardowe numeryczne
formatu, 252numeryczne formatu, 250parsowanie, 244pobieranie znaków, 222połączenia z jednostką, 371porównywanie, 225, 393puste, 221przeszukiwanie, 222standardowe formatu, 250tworzenie, 220zapisywanie deklaracji, 452znaków, 51
łączeniedekoratorów, 351łańcuchów, 223operatorów zapytań, 337sekwencji, 389
łącznik zadań, 603, 605łączność operatorów
lewostronna, 67prawostronna, 67
Mmagazyn danych, 611
komputera, 654kontenery, 655lokalny, 654odczyt i zapis, 655odizolowany, 650, 653podlegający roamingowi,
654położenie, 657sprawdzenie dostępności,
658strumieni, 617
makro, 468manifest
aplikacji .NET, 737–740podzespołu, 737, 738
mapowanieplików w pamięci, 650, 651struktury, 981
mechanizmcookies, 682konwersji, 257usuwania nieużytków, 485,
492, 498–502Close, 485Dispose, 485dostrajanie, 503działanie, 498IDisposable, 485wymuszenie działania, 502
metadane, 20składowych, 783
metoda, 18, 28, 88Abort, 911AddUsings(), 1028Aggregate, 427All, 430Any, 430AppendText(), 629Array.ConvertAll, 307Array.Sort, 306
AsEnumerable, 423AsParallel, 922Assert, 842Average, 426BinarySearch, 304Cancel(), 599, 600Cast, 421Clone, 307Close(), 487CodeAccessPermission.
RevertAssert, 859Combine(), 643ComputeHash, 865, 866Concat, 419Connect(), 692ConstrainedCopy, 307Consume, 957Contains, 430ContinueWith, 943Contract.Assert(), 529Contract.Assume(), 530Contract.EndContractBlock(),
526Contract.Ensures(), 527Contract.EnsuresOnThrow,
528Contract.OldValue<T>, 529Contract.Requires(), 523Contract.Requires<TExcepti
on>, 525Contract.Result<T>Contract.ValueAtReturn<T>,
528ConvertTime, 241Count, 425CreateDomain, 859CreateFileQueryWith
Options(), 648CreateText(), 629CreateViewAccessor(), 652DeepClone(), 707, 709DefaultIfEmpty, 425DefineMethodOverride, 811DefineType, 806Delay(), 599Delete(), 638Demand, 841, 842DescendantNodes(), 1020
Poleć książkęKup książkę
Skorowidz 1049
DisplayPrimeCounts(), 581Dispose(), 486, 490, 495Distinct, 394DoCallBack, 964Empty, 431Enqueue, 956EnsureInitialized, 908EqualityComparer<T>.
Default, 330Equals, 274, 276, 279Except, 420ExceptWith, 315ExecuteAssembly(), 771FindAll, 305FindAssembly(), 771First, 424FirstNode, 441Flatten, 949FlushFinalBlock, 870Foo(), 599, 811FormatOperand, 821GC.ReRegisterForFinalize(),
497get, 95GetAccessControl(), 640GetAsync(), 672GetAwaiter(), 574GetBankFee(), 882GetBytes, 866GetData, 910GetDiagnostics(), 1017GetEnumerator, 294GetEnumerator(), 658GetFileAsync(), 649GetFooValue, 832GetHashCode, 278, 319GetHostAddresses(), 690GetHostEntry(), 690GetKeyForItem, 325GetManifestResource
Names(), 756GetMembers, 780, 781GetObjectData(), 724GetPrimesCount(), 588GetResult(), 574GetType, 111Go(), 592GroupBy, 416
GroupJoin, 406, 409Handle, 950Increment, 881IndexOf, 305IndexOf/LastIndex, 304Interrupt, 911Intersect, 420IsEquivalentTo(), 1017IsMatch(), 994Join, 406Join(), 554Kind(), 1017Last, 424LastIndexOf, 305LastNode, 441Load, 436LoadFile(), 765, 766, 769LoadFrom(), 765, 766, 769,
771LongCount, 425Matches(), 994Max, 426Min, 426Monitor.Enter, 879, 880Monitor.Exit, 879Move(), 638MoveNext, 290Nodes, 441object.Equals, 274, 332Object.Equals, 273object.ReferenceEquals, 275OnCompleted(), 574OpenText(), 629OperationCompleted(), 595OperationStarted(), 595Parallel.For, 934Parallel.ForEach, 934, 935Parallel.Invoke, 933Parse, 245, 436ParseText(), 1018PrintAnswerToLife(), 591Queryable, 423Range, 431ReadElementString, 472ReadString, 472ReadSubtree, 472ReadToDescendant, 472ReadToFollowing, 472
ReadToNextSibling, 472ReadXml, 477ReadXml(), 735Regex.Match(), 994Regex.Replace(), 1003Register(), 600Repeat, 431Replace(), 1026Resume, 912Save, 807SaveChanges, 379Select, 395SelectMany, 399, 402, 403, 404SendAsync(), 672, 674SequenceEqual, 430set, 95SetAccessControll(), 640SetData, 910SetValue, 303SignalAndWait, 904, 905SignHash, 874Single, 424Skip, 393SkipWhile, 394Stop(), 487string.Format, 224SubmitChanges, 379Sum, 426Suspend, 912SymmetricExceptWith, 315Take, 393TakeWhile, 394Task.Delay(), 577Task.Run(), 570Task.WhenAny(), 603ToArray, 422ToDictionary, 422ToList, 422ToLookup, 422ToString, 112, 238, 245, 437ToString(), 1017ToXmlString, 873TryEnter, 880TryGetSwitch, 287TryParse, 245TryTake, 952Union, 419UnionWith, 315
Poleć książkęKup książkę
1050 Skorowidz
metodaWait(), 570WaitAll, 904, 942WaitAny, 904WhenAll(), 604Where, 391WindowFromPoint, 854WithChangedText(), 1026WriteAttributes(), 613WriteLine(), 629WriteValue, 475WriteXml(), 735metodyabstrakcyjne, 531agregacji, 390agregacyjne, 425anonimowe, 157asynchroniczne w WinRT, 594częściowe, 26, 100definicja, 100implementacja, 100destrukcyjne, 315do kategoryzacji znaków, 221dostępowe, 93, 95dostępowe zdarzenia, 148dostępowe zdarzeń, 152dynamiczne, 801egzemplarzowe, 181egzemplarzy, 142generujące, 430generyczne, 128, 790definiowanie, 814pobieranie, 787wywoływanie, 787instancji, 803, 810inwariantów obiektu, 520,
529, 530klasy Array, 304klasy DynamicObject, 834klasy Expression, 384klasy Math, 263klasy TimeZoneInfo, 241konwersji, 420krytycznebezpieczne, 850pod względem zabezpieczeń,
849ze względu na wydajność, 849
niebezpieczne, 853obiektu AssemblyName, 747OfType, 421przeciążanie, 89, 108przeszukiwania binarnego,
305ReadContentAsXXX, 471ReadXXX, 471rozszerzające, 180
łańcuchowe wywoływanie,181
metody egzemplarzowe,181
rozszerzeń, 25, 339skrótów, 619sortujące, 306statyczne, 142wczytujące, 471wirtualne, 273wtyczek, 140wyrażeniowe, 89
miejsca wywołania, 826MMC, Microsoft Management
Console, 544model
COM, 21kontraktu danych, 701obiektowy Reflection.Emit,
807programowania
asynchronicznego, 606semantyczny, 1030transparentności, 848, 849,
850wykonawczy PLINQ, 921
moduł sprawdzaniapisowni, 924
moduły, 740, 793współpracujące, 990
modyfikatorasync, 583internal, 114out, 62params, 63private, 114protected, 114protected internal, 114public, 114
readonly, 88ref, 61
modyfikatorydostępu, 114zdarzeń, 153
modyfikowaniedrzewa X-DOM, 444łańcuchów, 223węzłów atrybutów, 445węzłów potomnych, 445domen aplikacji, 965dziennika zdarzeń, 543
MSMQ, 216multiemisja, 141MVC, Model-View-Controller, 212
Nnadawca, 147nadpisane metody, 527, 529nadsubskrypcja procesora, 568nakładanie blokad, 558narzędzia
do generowania jednostek,375
Visual Studio, 761narzędzie signtool.exe, 750natywne biblioteki DLL, 973nawigacja, 440
do rodzica, 443na tym samym poziomie, 444po atrybutach, 444
nazwaelementów, 714kontraktu danych, 705pliku, 619podzespołów, 745symbolu, 1036typów generycznych, 776typów osadzonych, 776typów parametrów, 777wskaźników, 777
niebezpieczny kod, 194niegeneryczny słownik, 320niejawne
określanie typów, 65parametry ref, 988typowane zmienne lokalne,
25
Poleć książkęKup książkę
Skorowidz 1051
niepowodzenie, 515nieskończoność, 48niestandardowe
komparatory równości, 419łańcuchy formatu, 250
numeryczne łańcuchy formatu,250
Oobiekt, 58
AssemblyName, 746CollectionDataContract, 714CredentialCache, 677HttpClient, 680MailMessage, 691MemberInfo, 781szyfrowania, 870typu DateTime, 235typu DateTimeOffset, 236WebClient, 678WebRequest, 678WebResponse, 678
obiektowość, 17obiekty
dynamiczne, 833klasy Encoding, 230, 231niezmienne, 891potomne, 729
obliczanie skrótów, hashing,864–866
obsługałańcuchów i tekstu, 219wyjątków, 561, 678, 805zdarzeń, 587
oczekiwanie, 583na interfejs użytkownika, 585na zadania, 903
odbiorca, 188odczyt
danych licznika wydajności,546
elementów, 469plików .resources, 758
odizolowany magazyn danych,653
odwołaniado bibliotek DLL, 973do obiektu, 708
do składowych, 202do typów, 202wsteczne, 1011
ograniczaniedostępności, 115innego zestawu, 856
ograniczeniadotyczące klasy bazowej, 130dotyczące klasy i struktury,
131dotyczące konstruktora
bezparametrowego, 131dotyczące typu nagiego, 131kolekcja blokująca, 954modyfikatorów dostępu, 116PLINQ, 924typów generycznych, 130
określanie obiektu stanu, 940opakowanie, 327
zapytań, 358opcja Baseline, 537opcje
wyrażeń regularnych, 996,1011
zmiennej statycznej, 512operacje
asynchroniczne, 577na plikach i katalogach, 637synchroniczne, 577wejścia-wyjścia, 209, 648, 844
operator, 33, 65, 68–70&, 174!=, 273|, 174<, 281, 283==, 273, 276>, 283as, 103AsEnumerable, 367AsQueryable, 383is, 104Join, 407mnożenia, 29nameof, 100null, 70, 175OrderBy, 414OrderByDescending, 414ThenBy, 414
ThenByDescending, 414trójargumentowy, 51typeof, 111, 129warunkowy, 51warunkowy null, 23, 70wskaźnika do składowej, 196zapytania, 335
operatoryagregacji, 343arytmetyczne, 45bitowe, 47elementów, 342, 390, 423inkrementacji i
dekrementacji, 45konwersji, 348LINQ, 387porównywania i równości,
49, 173przypisania, 67relacyjne, 174sprawdzania przepełnienia
całkowitoliczbowego, 46warunkowe, 50wyliczeń, 123zbiorów, 390, 419zmieniające kształt, 389
opóźnienie podpisania, 744optymalizacja, 499, 596
PLINQ, 928własnych agregacji, 931z wartościami lokalnymi, 938
osadzanie typówwspółpracujących, 990
ostrzeżenia pragma, 199
Ppakiet NuGet, 1013pakowanie, 110, 120pamięć, 40
lokalna wątku, 909niezarządzana, 981współdzielona, 651, 978
paralelizm strukturalny, 918parametr, 28, 57, 60
lockTaken, 880out, 787ref, 787, 988
Poleć książkęKup książkę
1052 Skorowidz
parametryatrybutu, 192metod, 786nazwane, 192opcjonalne, 24, 63, 92, 987pozycyjne, 192typów, 126, 128, 132
parsowanie, 244, 255argumentów, 801IL, 819liczb, 258przez dostawcę formatu, 248
pary zastępcze, 231PCL, Portable Class Libraries, 19pewność przypisania, 59pętla
do-while, 76for, 76foreach, 77while, 76
pętlewewnętrzne, 935zewnętrzne, 935
PFX, 917PIA, primary interop assembly,
990piaskownica, 22pieczętowanie funkcji i klas, 106pierwszy program, 27planista
domyślny, 947kontekstu synchronizacji,
947zadań, 947
planowanie zadań, 947platforma
.NET Framework, 19, 205
.NET Core, 19plik, 649
.resources, 757
.resx, 757signtool.exe, 750XSLT, 483
pliki.edmx, 370.pdb, 540.tlb, 991.winmd, 737
metadanych, 22ZIP, 636
plikowe operacjewejścia-wyjścia, 648, 650
PLINQ, 918, 920anulowanie zapytania, 927kolejność elementów, 923ograniczenia, 924optymalizacja, 928wykonywanie równoległe,
922zastosowania, 926
płytkie kopiowanie, 302pobieranie
atrybutów w czasiedziałania, 797
elementów, 441elementów potomnych, 442jednego elementu, 442metadanych składowych,
783metod generycznych, 787typów osadzonych, 774typów tablicowych, 775wartości wyliczenia, 268znaków, 222
poczta elektronicznaotrzymywanie, 695wysyłanie, 691
podklasyobiektów potomnych, 731typu głównego, 730
podmiot zabezpieczeń, 862podnoszenie uprawnień, 846,
862podpisy cyfrowe, 874podpisywanie kodu, 750podstawowa przestrzeń
wielojęzyczna, BMP, 231podstawowe zestawy
międzyoperacyjne, 25podwyrażenia, 1002podzapytania, 353, 397podzespoły, 737, 738
atrybuty, 739emitowanie, 805ładowanie, 793manifest aplikacji, 739
manifest podzespołu, 738moduły, 740, 793nazwa, 745nazwa kwalifikowana, 746opóźnienie podpisania, 744podpisywanie, 742refleksje, 792repozytorium GAC, 753satelickie, 754, 760silne nazwy, 743ustalanie, 763użycie Authenticode, 749w pojedynczym pliku, 769wczytywanie, 762, 764wdrażanie, 768wersja informacyjna, 747współpracujące COM, 986wyszukiwanie, 762zapisywanie, 807
podział tekstu, 1004pola egzemplarzowe, 910pole, 35, 87polecenie, Patrz instrukcjapolimorfizm, 101
jednokierunkowy, 831wielokierunkowy, 831
ponawianie zgłoszenia wyjątku,163
ponowne obliczanie, 348POP, Post Office Protocol, 663POP3, 695poprawa wydajności, 788poprawność pliku XML, 481porównywanie
krotek, 270łańcuchów, 53, 225, 383
kulturowe, 225pod względem kolejności,
227pod względem równości,
226porządkowe, 225, 282
portyTCP, 664UDP, 664
porządkowanie, 413naturalne, 342
pośrednik, 327
Poleć książkęKup książkę
Skorowidz 1053
potokianonimowe, 622, 624nazwane, 622, 623
poziom zaufania, 846pożyczanie operatorów, 173praca zdalna, Remoting, 968
międzyprocesowa, 968prefiksy adresów URI, 670procesy, 539profil referencyjny, 21programowanie
asynchroniczne, 578, 579, 606dynamiczne, 210, 825funkcyjne, 18równoległe, 211, 551, 917,
920programy
typu klient, 552wielowątkowe, 552
progresywne budowaniezapytań, 356
projekcja, 394do typów konkretnych, 398do X-DOM, 459z indeksowaniem, 396
protokołydołączane, 273porządkowania, 328równości, 273, 328
protokółHTTP, 662, 680MIDI, 978POP3, 695SetLastError, 980TCP, 664, 692, 697UDP, 664
przechwytywaniestanu lokalnego, 584zdarzeń, 647zmiennych, 349, 560zmiennych iteracyjnych, 156zmiennych zewnętrznych, 155
przeciążaniekonstruktorów, 90metod, 89, 108operatorów, 177, 279
false, 179porównywania, 178
równości, 178true, 179
przedrostek, 454, 457przeglądanie słownika, 319przekazywanie
danych, 672danych formularza, 681przez referencję, 61, 89przez wartość, 60, 89nadmierne, 598stanu, 837wyjątku, 595
przeliczalność, 289przeliczanie, 347przełączanie kontekstu, 555przepełnienie
całkowitoliczbowe, 45przerwanie operacji, 598przesłanianie metody, 278, 279przestrzenie nazw w XML, 453przestrzeń nazw, 29, 79
aliasy, 83globalna, 80import, 83kwalifikatory aliasów, 84powtarzanie, 82kontraktu danych, 706System.ComponentModel,
566System.Cryptography, 868System.Diagnostics, 209System.Reflection, 741System.Reflection.Emit, 807System.Runtime.Serialization,
703System.Text, 208System.Text.Regular
Expressions, 993System.Xml, 465właściwości
zaawansowane, 83zakres, 81
przeszukiwaniedrzewa, 1019łańcuchów, 222tablic, 304
przetwarzanie tekstu, 208przewidywanie, 999
negatywne, 1000
pozytywne, 1000wsteczne, 999
przypisywanieatrybutów, 813ról, 863użytkowników, 863wielu atrybutów, 192
przyrostki literałów liczbowych,43
przysłanianie metod, 810pula wątków, 567punkty kontrolne, 538
RRCW, runtime-callable wrappers,
986rdzeń platformy, 207receptury wyrażeń regularnych,
1005refaktoryzacja, 28referencja this, 92refleksje, 210, 773, 780
atrybutów, 798dla podzespołów, 792składowych, 781
reguły asynchroniczności, 577reimplementacja interfejsu, 118rekurencja blokowania, 897Remoting, 217repozytorium GAC, 752, 753reprezentacja typu dynamic, 186responsywny interfejs
użytkownika, 551REST, REpresentational State
Transfer, 663rodzaje
kodowania tekstu, 229serializatorów, 704uprawnień, 840węzłów, 475
role, 862Roslyn
architektura, 1014drzewa składni, 1015kompilacja, 1030model semantyczny, 1030przestrzenie robocze, 1014
Poleć książkęKup książkę
1054 Skorowidz
rozgałęzianie, 803rozpakowywanie, 110rozpoznawanie, 108rozszerzanie interfejsu, 117rozszerzenie kontraktu danych,
715równoległe wykonywanie zadań,
939równoległość, 592równość, 279
referencyjna, 272, 273refleksyjna, 276strukturalna, 272wartościowa, 272, 273
równoważenie obciążenia, 930równoważność typów, 990rzutowanie, 37, 102, 679
w dół, 103w górę, 102
Ssekcja CDATA, 468sekwencje, 171, 389
dekoracyjne, 350filtrowanie, 389grupowanie, 390lokalne, 335łączenie, 389porządkowanie, 389projekcja, 389specjalne, 51wyjściowe, 335zagnieżdżone, 389
selektywne egzekwowaniekontraktów, 534
semafory, 892semantyka iteratorów, 168serializacja, 210, 437, 699
atrybuty, 720binarna, 701, 718jawna, 703kolekcji, 732kontraktu danych, 701, 703niejawna, 703obiektów potomnych, 730odwołań do obiektów, 708podklas, 707
tworzenie podklas, 726typów generycznych, 722XML, 727za pomocą ISerializable, 724zaczepy, 715
serializatorDataContractSerializer, 704NetDataContractSerializer,
704serializator kontraktu danych,
717serwer
FTP, 688HTTP, 685POP3, 695proxy, 675SMTP, 691
serwerowe środowiskouruchomieniowe, 501
sieć, 209, 661silne nazwy, 742silnik XML, 702silniki serializacji, 700Silverlight, 214sklep Windows Store, 650skład zapytania
interpretowanego, 365składnia, 30
płynna, 337, 346SQL, 346zapytaniowa, 344, 346
składnikiPFX, 919platformy .NET, 864
składoweabstrakcyjne, 105C#, 784CLR, 784egzemplarza, 35funkcyjne, 18interfejsu, 116interfejsu generycznego, 790klasy Assembly, 742klasy object, 112klasy Stream, 613klasy TextReader, 628klasy TextWriter, 628niepubliczne, 788
odziedziczone, 105prywatne, 36statyczne, 35, 889typów generycznych, 785typu, 35
skompilowane typy, 737skrót, 278skrypt, 837słabe odwołania, 507, 508słowa kluczowe, 30
kontekstowe, 32słowa zarezerwowane, 30słowniki, 316
sortowane, 321słowo kluczowe
async, 582async i await, 582await, 583base, 107, 108Component, 759dynamic, 827extern, 83fixed, 984into, 358let, 361new, 106, 803override, 106public, 36ref, 988stackalloc, 196static, 827using, 1027var, 65virtual, 104volatile, 983
SMTP, Simple Mail TransferProtocol, 663, 691
sortowanie, 306, 415spinning, 555sprawdzanie
granic tablic, 57modelu semantycznego,
1032poprawności dokumentu,
481poprawności drzewa X-DOM,
483poprawności schematów, 480
Poleć książkęKup książkę
Skorowidz 1055
poziomu zaufania, 846przepełnienia, 46równości, 271, 277sposobu kodowania, 230typów, 971dostępnych liczników, 545kontraktu, 536w miejscu wywołania, 535
SSL, 685stała, 33, 96stan
lokalny, 556, 584współdzielony, 556
standardowełańcuchy formatu, 250operatory zapytań, 335
standardowy wzorzec zdarzeń,149
statyczna kontrola typów, 18,111
statyczne sprawdzeniekontraktu, 536
sterta, 58ogromnych obiektów, 500
stos, 57, 313ewaluacji, 800LIFO, 313
stosowanieblokady, 881zasad dostępu kodu, 845
strategiedziedziczenia, 370projekcji, 360
strefy czasowe, 239, 242struktura, 113
BigInteger, 264Complex, 264DateTime, 233, 239, 243DateTimeOffset, 233, 239DOM wyrażenia, 383drzewa, 1019Guid, 271Nullable<T>, 172SyntaxToken, 1015SyntaxTree, 1015SyntaxTrivia, 1016TextSpan, 1022TimeSpan, 232
strukturalna równośćwartościowa, 277
strukturalne zrównoleglanieprzetwarzania danych, 918
strumienie, 209adapter, 626architektura, 611bezpieczeństwo wątków, 617dekoracyjne, 612kompresja, 634limit czasu, 617magazynu danych, 612, 617obsługa odczytu i zapisu,
615opróżnienie, 616wyszukiwanie, 616zamknięcie, 616zamykanie adapterów, 633
strumieniowanie projekcji, 461strumień
BufferedStream, 625FileStream, 618MemoryStream, 621PipeStream, 622XmlReader, 467
subkultury, 762subskrybent, 147surogat, 231sygnalizacja, 878, 897, 898sygnały dwustronne, 899sygnatura metody, 88sygnatury Func, 341symbole, 1032
zadeklarowane, 1034symetria typów
predefiniowanych, 35symulowanie unii C, 977synchronizacja, 594, 878, 880system
CLR, 20plików
CDFS, 640FAT, 640NTFS, 640przechwytywanie
zdarzeń, 647typów COM, 985
szeregowanieIn i Out, 976klas i struktur, 975typów wspólnych, 974
szyfrowanie, 844kluczem publicznym, 871skrótów, 864SSL, 685symetryczne, 867w pamięci, 868wiadomości, 872
Śścisła kontrola typów, 19śledzenie obiektów, 373środowisko
uruchomieniowe CLR, 501wykonawcze systemu
Windows, 21
Ttabela operatorów, 67tablice, 53, 135, 196
bajtów, 231długość, 304indeksowanie, 302konwertowanie, 307kopiowanie, 307liczba wymiarów, 304nieregularne, 55odwracanie kolejności
elementów, 307prostokątne, 55przeglądanie zawartości, 304przeszukiwanie, 304skrótów, hash tables, 278,
319sortowanie, 306tworzenie, 302w pamięci, 301wielowymiarowe, 55zmienianie rozmiarów, 307
TAP, Task-based AsynchronousPattern, 602
TCP, Transmission and ControlProtocol, 663, 692, 697
Poleć książkęKup książkę
1056 Skorowidz
technikioptymalizacji, 499synchronizacji, 878wielowątkowości, 877
technologia.ASMX Web Services, 217ADO.NET, 214ASP.NET, 212Authenticode, 748COM+, 216EF, 379L2S, 379LINQ, 25, 208, 335MSMQ, 216PLINQ, 918Silverlight, 214WCF, 216WPF, 213XML, 465
technologieinterfejsu użytkownika, 212zapleczowe, 214
tekst, 208testowanie, 262
podzespołów satelickich, 761testy jednostkowe, 673token anulowania, 927tożsamości, 862transformacja drzewa składni,
1026transparentność, 848, 855tryb pliku, 619tworzenie
asercji, 515deasemblera, 819domen aplikacji, 961drobiazgów, 1027drzewa X-DOM, 437egzemplarzy, 35FileStream, 618funkcji asynchronicznych,
589instancji obiektów, 803instancji typów, 778kompilacji, 1030liczników wydajności, 547łańcuchów, 220
łańcuchów strumieniszyfrowania, 869
obiektów typu DateTime, 235obiektów typu
DateTimeOffset, 236pliku .resx, 758podklas typów generycznych,
131podzespołu satelickiego, 760serwera HTTP, 685struktur, 113tablic, 302tokenów, 1027typów, 87uchwytu EventWaitHandle,
902wątku, 552węzłów, 1027własnych fabryk zadań, 948wyrażeń lambda, 340wyrażeń zapytań, 357zadań, 940zapytań złożonych, 356zasobu pack URI, 759zbioru, 315złączeń, 407
typ, 33bool, 174char, 219CultureInfo, 247DateTimeFormatInfo, 247decimal, 48double, 47, 48dynamic, 186, 187float, 47NumberFormatInfo, 247object, 109, 186string, 52, 220TSource, 341var, 187wyliczeniowy
Environment.SpecialFolder,644
RegexOptions, 995UnmanagedType, 974WebExceptionStatus, 678
typizowanie elementów, 341
typyanonimowe, 25, 182, 360argumenty, 126bazowe, 777całkowitoliczbowe
16-bitowe, 478-bitowe, 47
częściowe, 99definiowane przez
programistę, 277delegacyjne, 139, 145dopuszczające wartość null,
171alternatywa, 176konwersje jawne, 172konwersje niejawne, 172mieszanie operatorów, 174operatory null, 175pakowanie wartości, 172rozpakowywanie wartości,
172zastosowania, 175
generyczne, 125, 276, 776,779dane statyczne, 132definiowanie, 815delegacyjne, 143niezwiązane, 129, 780odwołania do samego
siebie, 132ograniczenia, 130podklasy, 131szablony C++, 137zamknięte, 780, 816
izolacji, 653logiczne, 49liczbowe, 42, 827osadzone, 775otwarte, 126parametry, 126, 128platformy .NET Framework,
887predefiniowane, 34proste, 41referencyjne, 37, 39, 41, 54składowych, 782statyczne, 189
Poleć książkęKup książkę
Skorowidz 1057
systemowe, 207tablicowe, 135, 775wartościowe, 37, 38, 41, 54węzłów, 1017własne, 35wskaźnikowe, 194współpracujące, 990współpracujące COM, 986wyjątków, 164wyrażeń, 384X-DOM, 435zagnieżdżone, 124zamknięte, 126zwrotne, 28, 139
UUAC, User Account Control, 860uchwyt EventWaitHandle, 902uchwyty zdarzeń oczekiwania,
897, 899, 902udostępnianie obiektów, 991UDP, Universal Datagram
Protocol, 663ukończenie synchroniczne, 596ukrywanie
nazw, 81odziedziczonych
składowych, 105UNC, Universal Naming
Convention, 663unia, 978Unicode, 229unifikacja, 109
typów liczbowych, 827unikanie konfliktów nazw, 32uprawnienia, 839
diagnostyczne, 844dla operacji wejścia i wyjścia,
844dostępu kodu, 839dotyczące interfejsu
użytkownika, 844dotyczące szyfrowania, 844dotyczące tożsamości, 845podstawowe, 843sieciowe, 844UIPermission, 854
URI, Uniform ResourceIdentifier, 663
URL, Uniform Resource Locator,663
uruchamianie zadań, 570, 940usługa, 370ustalanie typu, 763ustawianie stopnia
zrównoleglenia, 927ustawienia przezroczystości, 852usuwanie
elementów składowych, 490nieużytków, 485, 498
automatyczne, 491Close, 485Dispose, 485IDisposable, 485
obiektów, 373sekwencji atrybutów, 446sekwencji węzłów, 446
UTF-16, 231uwierzytelnianie, 676
na podstawie formularzy,684
HttpClient, 678nagłówki, 678
uzgadnianie klucza publicznego,872
uzyskanie drzewa składni, 1018używanie
Authenticode, 749biblioteki PFX, 920delegatów, 140delegatu multiemisji, 142DNS, 690FTP, 688klamer, 73klasy XmlWriter, 480kontraktów kodu, 519, 532PLINQ, 926punktów kontrolnych, 538serializatorów, 704strumieni, 613TCP, 692uchwytów zdarzeń
oczekiwania, 897
VVoice over IP, 692
Wwariancja, 134
parametrów, 146typów, 24
warstwy sekwencji dekoratorów,351
wartości, 447domyślne, 59pobieranie, 448specjalne typów liczbowych,
47ustawianie, 447zwrotne, 571
wartośćNaN, 48Null, 40, 171, 238, 712skrótu, hash code, 278
warunkikontraktu
wyjątki, 534końcowe, 527, 529początkowe, 523, 527
wątek, 211, 552, 965bezpieczeństwo, 558blokowanie, 555dołączanie, 554priorytet, 563przekazywanie danych, 559sygnalizowanie, 564usypianie, 554wywłaszczenie, 553
wątkidziałające w tle, 562aktywne, 562interfejsu użytkownika, 566procesów, 539pula, 567w aplikacjach WPF, 564
wątkowanie, 552WCF, Windows Communication
Foundation, 216wczesne ładowanie, 378
w Entity Framework, 379
Poleć książkęKup książkę
1058 Skorowidz
wczytywanieatrybutów, 472podzespołu, 764węzłów, 467
wdrażanie podzespołów, 768Web API, 217wektor inicjalizujący, IV, 868wersjonowanie, 723, 753weryfikacja Authenticode, 751węzły
atrybutów, 473potomne, 441XML, 467XText, 449z treścią mieszaną, 449
wiązaniedynamiczne, 24, 183, 989językowe, 185niestandardowe, 185statyczne, 184
wielowątkowość, 877Windows Data Protection, 864Windows Forms, 213Windows RT i Xamarin, 214Windows Store, 650Windows Workflow, 215WinRT, 21, 493wirtualizacja, 862wirtualne składowe funkcyjne, 104własne
atrybuty, 796fabryki zadań, 948liczniki wydajności, 548łączniki zadań, 605
własności, 18, 29, 93automatyczne, 26, 94klasy System.Exception, 164obliczane, 94otoczenia, 175tylko do odczytu, 94wyrażeniowe, 94
właściwości adresu URI, 665właściwość
CodeBase, 767IsGenericType, 780IsGenericTypeDefinition,
780Location, 767
MethodHandle, 782Span, 1017SyntaxTree, 1017
WPF, Windows PresentationFoundation, 213
wpisywanieatrybutów, 475węzłów, 475
wskaźnik, 777do kodu niezarządzanego,
197do składowej, 196pusty, 197
wskrzeszenie, 496współbieżność, 209, 551
drobnoziarnista, 579gruboziarnista, 579, 588w TCP, 694
współpraca COM, 985wtyczka, 140wybór
obiektu synchronizacji, 880trybu pliku, 620
wychodzenie z pętli, 936wyciek
blokady, 880pamięci zarządzanej, 503
wydajność, 788, 885, 901wyjątek, 158, 534, 572, 805
AggregateException, 949ContractException, 522, 525FormatException, 245niezaobserwowany, 572NullReferenceException,
274, 461RuntimeBinderException,
186TypeLoadException, 818UnauthorizedAccess
Exception, 861WebException, 678XmlException, 469
wykonywanieleniwe, 348opóźnione, 347, 350, 356, 376równoległe, 922spekulatywne, 552zapytania, 352
wykorzystanie delegatów, 788wyliczenia, 121, 166
atrybut Flags, 122konwersje, 121, 267operatory, 123
wyliczenieBindingFlags, 789DateTimeStyles, 256TaskCreationOptions, 941
wymagania modelutransparentności, 852
wynik obliczeń, 28wyrażenia, 27, 65
dynamiczne, 188inicjalizacji tablicy, 54, 56lambda, 18, 25, 153, 340, 560,
593jawne określanie typów, 154przechwytywanie
zmiennychzewnętrznych, 155
podstawowe, 66przypisania, 66puste, 66regularne, 993
alternatywy, 1011asercje, 999, 1010granica słowa, 1001grupy, 1002kategorie znaków, 1009kompilowane, 995konstrukcje grupujące,
1010konstrukcje różne, 1011kotwice, 1000kwantyfikatory, 1009nazwane grupy, 1003odwołania wsteczne, 1011opcje, 996, 1011receptury, 1005–1008zastąpienia, 1010zbiory znaków, 1009zestawy znaków, 997znaki sterujące, 996, 1008
stałe, 66typy statyczne, 189zapytań, 18, 25, 337, 343, 357,
381
Poleć książkęKup książkę
Skorowidz 1059
wysyłanie zapytań, 440wyszukiwanie
elementu potomnego, 1021podzespołów, 762symboli, 1036
wyświetlenie podpisuAuthenticode, 751
wywołaniaanonimowe, 831asynchroniczne, 591dynamiczne, 188komponentu COM, 986konstruktorów bazowych,
813metod generycznych, 787metod instancji, 803składowych, 780, 786składowych interfejsu
generycznego, 790zwrotne, 977
wzorceasynchroniczności, 598
oparte na zadaniu, 602oparte na zdarzeniach, 607
przestarzałe, 606wzorzec
metod TryXXX, 165UnsafeXXX, 851wizytator, 828
XX-DOM, 434
automatyczne głębokieklonowanie, 439
definiowanie przestrzeninazw, 455
domyślne przestrzenie nazw,456
klasa XmlReader, 479klasa XmlWriter, 479konstrukcja funkcyjna, 438ładowanie, 436modyfikowanie drzewa, 444nawigacja do rodzica, 443nawigacja na tym samym
poziomie, 444nawigacja po atrybutach, 444
nawigowanie, 440parsowanie, 436przekształcanie drzewa, 462serializacja, 437sprawdzanie poprawności,
483tworzenie drzewa, 437wysyłanie zapytań, 440zapisywanie, 437
XML, 208, 465dokumentacja, 200
XSD, XML Schema Definition,480
XSLT, Extensible StylesheetLanguage Transformations,483
Zzabezpieczenia
dostępu kodu, 843niebezpiecznych metod, 853systemu operacyjnego, 860
zaczepy serializacji, 715zadania, 569
autonomiczne, 572anulowanie, 942długo wykonywane, 571kontynuacje, 943, 945kontynuacje na jednym
przodku, 947kontynuacje warunkowe,
945kontynuacje z wieloma
przodkami, 947planowanie, 947potomne, 941, 945równoległe wykonywanie,
939sposób wykorzystania, 956tworzenie, 940uruchamianie, 570, 940zimne, 956
zadanie Task<TResult>, 944zagnieżdżanie
blokad, 883dyrektywy using, 82
zakleszczenia, 884
zależności cykliczne, 817zamykanie
adapterów, 633egzemplarzy nasłuchujących,
518zapisywanie deklaracji, 452zapytania, 208
EF, 376interpretowane, 362, 364L2S, 376LINQ, 335o składni mieszanej, 347złożone, 356
zarządzaniekluczami, 871pamięcią, 19
zasadydostępu kodu, 845zabezpieczeń, 855
zasoby, 755zasób pack URI, 759zastąpienia, 1010zastępowanie tekstu, 1003zastosowania
biblioteki PFX, 920typów dopuszczających
wartość null, 175klasy XmlReader, 476klasy XmlWriter, 476
zbiory, 314, 419znaków, 1009
zdarzenia, 29, 147, 508metody dostępowe, 152modyfikatory, 153wzorzec standardowy, 149
zdarzenia systemu plików, 647zdarzenie, 18
AssemblyResolve, 764, 769ContractFailed, 533EntryWritten, 543IncludeSubdirectories, 647
zegary, 505, 913jednowątkowe, 915wielowątkowe, 913
zestaw referencyjny, 22zestawy, 210
zaprzyjaźnione, 115znaków, 997
Poleć książkęKup książkę
1060 Skorowidz
zgłaszanie wyjątków, 162zgodność
delegatów, 145parametrów, 145typów, 145typów zwrotnych, 146
złączenia, 397, 406krzyżowe, 407nierównościowe, 407płaskie zewnętrzne, 411w składni płynnej, 409według wielu kluczy, 409wewnętrzne, 407z widokami wyszukiwania,
411zewnętrzne, 404zewnętrzne lewe, 407
złożonełańcuchy formatu, 224operatory przypisania, 66
zmienianiedefinicji równości, 277nazwy symbolu, 1036ścieżki wykonywania, 73
zmienne, 33, 57iteracyjne, 156lokalne, 28, 65, 72, 557, 802zakresowe, 344, 345, 358, 401zewnętrzne, 155
znacznikidokumentacyjne XML, 201niestandardowe, 202
znakiinterpunkcyjne, 32podwójne, 231sterujące, 996, 1008
znakowanie czasowe, 750zrównoleglanie, 927
przetwarzania danych, 918wykonywania zadań, 918
zużycie pamięci, 492zwalnianie zasobów, 485–488
na żądanie, 489zwrot egzemplarza, 590
Żżądanie uprawnień, 857
Poleć książkęKup książkę