Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00056 006318 19007551 na godz. na dobę w sumie
Język C# w 7 dni. Solidne podstawy programowania obiektowego - książka
Język C# w 7 dni. Solidne podstawy programowania obiektowego - książka
Autor: Liczba stron: 264
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-4356-6 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> c# - programowanie
Porównaj ceny (książka, ebook (-35%), audiobook).

Język C# to nowoczesne narzędzie programowania obiektowego stworzone przez Microsoft. Wyjątkowo przydatne, wielofunkcyjne i powszechnie używane. Także ze względu na wieloplatformowość i otwartą specyfikację. Jednak najważniejsze, że wystarczy gruntownie opanować podstawy języka C# i już możesz tworzyć solidne i wydajne aplikacje zarówno do zastosowań desktopowych, jak i na urządzenia mobilne! To świetna wiadomość i dla początkujących programistów, i dla tych, którzy postanowili poznać nowy język.

Ten podręcznik ułatwi Ci szybkie opanowanie podstaw języka C#. Autor, doświadczony guru IT, Gaurav Aroraa, proponuje 7-dniowy plan działania, którego realizacja da Ci pełne spektrum umiejętności programistycznych. Zacznij już teraz kurs języka C#! Językowa biegłość przyniesie Ci satysfakcję i pewność siebie, poprawi Twoją pozycję w zespole czy na rynku pracy.

Podstawy języka C# w 7 dni!

W 7 dni przejdziesz intensywny kurs:


Gaurav Aroraa w ciągu prawie 20-letniej kariery był mentorem tysięcy studentów informatyki i branżowych specjalistów. Jest Microsoft MVP jako trener Scrum, XEN w zastosowaniach ITIL-F. Ma certyfikaty PRINCE-P i PRINCE-F APMG. Tworzy treści w TechNet Wiki. Jest jednym z założycieli firmy Innatus Curo Software LLC.

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

Darmowy fragment publikacji:

Tytuł oryginału: Learn C# in 7 days Tłumaczenie: Piotr Rajca ISBN: 978-83-283-4356-6 Copyright © Packt Publishing 2017. First published in the English language under the title ‘Learn C# in 7 days – (9781787287044)’ Polish edition copyright © 2018 by Grupa Helion All rights reserved. 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łe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/jezc7d.zip Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/jezc7d Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:258)ci O autorach O recenzencie Wst(cid:218)p Rozdzia(cid:239) 1. Dzie(cid:241) 1. — Przegl(cid:200)d platformy .NET Czym jest programowanie? Czym jest .NET? Czym jest .NET Core? Cechy .NET Core Z czego sk(cid:239)ada si(cid:218) .NET Core? Czym jest .NET Standard? Dost(cid:218)pne (cid:258)rodowiska programistyczne i edytory do pisania kodu w C# Przygotowywanie (cid:258)rodowiska (cid:109)wiczenia praktyczne Podsumowanie dnia 1. Rozdzia(cid:239) 2. Dzie(cid:241) 2. — Zaczynamy poznawa(cid:202) C# Przedstawienie j(cid:218)zyka C# Historia j(cid:218)zyka C# Przedstawienie typowego programu C# 1 (System) 2 (Dzien02) 3 (Program) 4 (Main) 5 (Dzien02) 6 (Dzien02) 7 (Zale(cid:285)no(cid:258)ci) 8 (Program.cs) Dok(cid:239)adniejsze poznanie aplikacji z u(cid:285)yciem Visual Studio Analiza kodu 9 10 13 15 15 17 18 18 19 19 20 21 23 23 25 26 27 27 29 30 31 31 31 32 33 34 34 36 Poleć książkęKup książkę Spis tre(cid:286)ci Przegl(cid:200)d s(cid:239)ów kluczowych, typów i operatorów j(cid:218)zyka C# Identyfikatory Kontekstowe s(cid:239)owa kluczowe Typy Operatory Przegl(cid:200)d informacji o konwersji typów Konwersja niejawna Konwersja jawna Prezentacja instrukcji Instrukcja deklaracji Instrukcja wyra(cid:285)enia Instrukcje wyboru Instrukcja obs(cid:239)ugi wyj(cid:200)tków Operacje na tablicach i (cid:239)a(cid:241)cuchach znaków Tablice Typy tablic (cid:146)a(cid:241)cuchy znaków Struktury a klasy (cid:109)wiczenia praktyczne Podsumowanie dnia 2. Rozdzia(cid:239) 3. Dzie(cid:241) 3. — Co nowego w C#? Krotki i dekonstrukcja Krotki Dekonstrukcja Krotki — wa(cid:285)ne zagadnienia do zapami(cid:218)tania Dopasowywanie wzorców Wyra(cid:285)enie is Instrukcja switch Funkcje lokalne Usprawnienia litera(cid:239)ów Litera(cid:239)y dwójkowe Separatory cyfr Asynchroniczna metoda Main Ograniczenia zwi(cid:200)zane z nowymi sygnaturami Wyra(cid:285)enia domy(cid:258)lne Zmienne sk(cid:239)adowe Wnioskowanie nazw krotek Inne planowane mo(cid:285)liwo(cid:258)ci Dopasowywanie wzorców z typami ogólnymi Zestawy referencyjne (cid:109)wiczenia praktyczne Podsumowanie dnia 3. 4 38 39 51 53 57 64 65 65 66 67 68 68 76 76 76 78 81 82 85 87 89 89 90 94 95 96 97 99 102 103 103 104 105 106 106 107 108 110 110 111 111 112 Poleć książkęKup książkę Spis tre(cid:286)ci Rozdzia(cid:239) 4. Dzie(cid:241) 4. — Prezentacja sk(cid:239)adowych klas w j(cid:218)zyku C# Modyfikatory Modyfikatory oraz poziomy dost(cid:218)pu Regu(cid:239)y zwi(cid:200)zane ze stosowaniem modyfikatorów dost(cid:218)pu Modyfikator abstract Modyfikator async Modyfikator const Modyfikator event Modyfikator extern new Modyfikator override Modyfikator partial Modyfikator readonly Modyfikator sealed Modyfikator static Modyfikator unsafe Modyfikator virtual Metody Jak nale(cid:285)y u(cid:285)ywa(cid:202) metod? W(cid:239)a(cid:258)ciwo(cid:258)ci Rodzaje w(cid:239)a(cid:258)ciwo(cid:258)ci Indeksery Operacje wej(cid:258)cia-wyj(cid:258)cia na plikach Klasa FileStream Obs(cid:239)uga wyj(cid:200)tków Blok try Blok catch Blok finally Wyj(cid:200)tki definiowane przez u(cid:285)ytkownika Wyra(cid:285)enia regularne oraz ich znaczenie Znaczenie wyra(cid:285)e(cid:241) regularnych (cid:109)wiczenia praktyczne Podsumowanie dnia 4. Rozdzia(cid:239) 5. Dzie(cid:241) 5. — Przegl(cid:200)d informacji o odzwierciedlaniu i kolekcjach Czym jest odzwierciedlanie? Praktyczne stosowanie odzwierciedlania Przegl(cid:200)d informacji o delegacjach i zdarzeniach Delegacje Zdarzenia Kolekcje i typy nieogólne ArrayList Hashtable SortedList 113 115 115 122 123 127 127 128 128 128 129 129 130 131 133 134 134 135 135 138 139 143 144 144 145 147 147 147 149 151 151 154 155 157 157 161 166 166 169 170 171 173 176 5 Poleć książkęKup książkę Spis tre(cid:286)ci Stack Queue BitArray (cid:109)wiczenia praktyczne Podsumowanie dnia 5. Rozdzia(cid:239) 6. Dzie(cid:241) 6. — Dok(cid:239)adniejszy przegl(cid:200)d zagadnie(cid:241) zaawansowanych Stosowanie kolekcji i typów ogólnych Prezentacja klas kolekcji oraz sposobów ich stosowania Wydajno(cid:258)(cid:202) — BitArray a tablica typu bool Prezentacja typów ogólnych oraz ich zastosowania Upi(cid:218)kszanie kodu przy u(cid:285)yciu atrybutów Typy atrybutów Tworzenie i stosowanie niestandardowych atrybutów Stosowanie dyrektyw preprocesora Wa(cid:285)ne zagadnienia Prezentacja LINQ Pisanie niebezpiecznego kodu Pisanie asynchronicznego kodu (cid:109)wiczenia praktyczne Podsumowanie dnia 6. Rozdzia(cid:239) 7. Dzie(cid:241) 7. — Podstawy programowania obiektowego w C# Wprowadzenie do programowania obiektowego Zwi(cid:200)zki pomi(cid:218)dzy obiektami Dziedziczenie Wyja(cid:258)nienie dziedziczenia Stosowanie dziedziczenia Abstrakcja Stosowanie abstrakcji Hermetyzacja Czym s(cid:200) modyfikatory dost(cid:218)pu w j(cid:218)zyku C#? Stosowanie hermetyzacji Polimorfizm Typy polimorfizmu Stosowanie polimorfizmu (cid:109)wiczenia praktyczne Podsumowanie dnia 7. Co dalej? Skorowidz 6 179 181 185 185 186 187 188 188 189 191 203 203 207 209 209 214 215 217 218 219 221 222 223 224 224 233 238 238 242 242 243 244 245 249 251 252 252 255 Poleć książkęKup książkę 6 Dzie(cid:241) 6. — Dok(cid:239)adniejszy przegl(cid:200)d zagadnie(cid:241) zaawansowanych Zaczynamy w(cid:239)a(cid:258)nie szósty dzie(cid:241) naszego siedmiodniowego kursu j(cid:218)zyka C#. W poprzednim rozdziale zaprezentowano wa(cid:285)ne zagadnienia j(cid:218)zyka C# — odzwierciedlanie, kolekcje, delegacje oraz zdarzenia. Zosta(cid:239)y one opisane i przedstawione na przyk(cid:239)adach. W tym rozdziale skoncen- trujemy si(cid:218) na kolejnych rodzajach kolekcji, zaimplementowanych jako typy ogólne; oprócz nich zaprezentujemy tak(cid:285)e dyrektywy preprocesora oraz atrybuty. W tym rozdziale zostan(cid:200) opisane nast(cid:218)puj(cid:200)ce zagadnienia: (cid:81) stosowanie kolekcji i typów ogólnych; (cid:81) upi(cid:218)kszanie kodu przy u(cid:285)yciu atrybutów; (cid:81) stosowanie dyrektyw preprocesora; (cid:81) prezentacja LINQ; (cid:81) pisanie niebezpiecznego kodu; (cid:81) pisanie kodu asynchronicznego. Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Stosowanie kolekcji i typów ogólnych Kolekcje nie s(cid:200) dla nas czym(cid:258) nowym, gdy(cid:285) w poprzednim rozdziale poznali(cid:258)my ju(cid:285) kolekcje zaimplementowane jako typy nieogólne. Jednak oprócz nich istniej(cid:200) tak(cid:285)e kolekcje b(cid:218)d(cid:200)ce typami ogólnymi. W(cid:239)a(cid:258)nie nimi zajmiemy si(cid:218) w tym podrozdziale, gdzie zostan(cid:200) dok(cid:239)adniej opisane i za- prezentowane na przyk(cid:239)adach. Prezentacja klas kolekcji oraz sposobów ich stosowania Zgodnie z informacjami podanymi w pi(cid:200)tym dniu kursu, kolekcje to wyspecjalizowane klasy s(cid:239)u(cid:285)(cid:200)ce do operacji na danych (ich przechowywania oraz pobierania). W poprzednim rozdziale przedstawionych ju(cid:285) zosta(cid:239)o kilka rodzajów kolekcji, a konkretnie: stos, kolejka, lista, tablica mie- szaj(cid:200)ca, wchodz(cid:200)cych w sk(cid:239)ad przestrzeni nazw System.Collections.NonGeneric. Zamieszczona poni(cid:285)ej tabela 6.1 zawiera zestawienie kilku nieogólnych klas kolekcji wraz z opisem ich stosowa- nia oraz przeznaczenia. Tabela 6.1. Klasy kolekcji Klasa Opis ArrayList Ta kolekcja zawiera uporz(cid:200)dkowan(cid:200) list(cid:218) obiektów, do których mo(cid:285)na si(cid:218) odwo(cid:239)ywa(cid:202) przy u(cid:285)yciu indeksów. Kolekcj(cid:218) tego typu mo(cid:285)na zadeklarowa(cid:202) w nast(cid:218)puj(cid:200)cy sposób: ArrayList arrayList = new ArrayList(); Hashtable to reprezentacja kolekcji zawieraj(cid:200)cej pary klucz – warto(cid:258)(cid:202), zorganizowane na podstawie klucza pe(cid:239)ni(cid:200)cego rol(cid:218) kodu mieszaj(cid:200)cego. Stosowanie tej kolekcji zaleca si(cid:218) w przypadkach, kiedy konieczne jest odwo(cid:239)ywanie si(cid:218) do danych na podstawie klucza. Poni(cid:285)ej przedstawiony zosta(cid:239) sposób deklarowania kolekcji tego typu: Hashtable hashtable = new Hashtable(); SortedList to reprezentacja kolekcji par klucz – warto(cid:258)(cid:202), zorganizowanej na podstawie kluczy, której zawarto(cid:258)(cid:202) jest posortowana wed(cid:239)ug tych kluczy. Kolekcja ta jest po(cid:239)(cid:200)czeniem kolekcji ArrayList oraz Hashtable; oznacza to, (cid:285)e do elementów tej kolekcji mo(cid:285)na si(cid:218) odwo(cid:239)ywa(cid:202) przy u(cid:285)yciu kluczy lub indeksów. Hashtable SortedList 188 Zastosowanie W drugim dniu kursu zosta(cid:239)y przedstawione tablice oraz sposoby odwo(cid:239)ywania si(cid:218) do ich poszczególnych elementów. W przypadku kolekcji ArrayList mo(cid:285)na skorzysta(cid:202) z ró(cid:285)nych metod dodawania do kolekcji i usuwania z niej elementów, które zosta(cid:239)y dok(cid:239)adniej opisane w pi(cid:200)tym dniu kursu. Kolekcja typu Hashtable jest najbardziej u(cid:285)yteczna w sytuacjach, kiedy trzeba odwo(cid:239)ywa(cid:202) si(cid:218) do danych przy u(cid:285)yciu klucza. W takich przypadkach dysponujemy kluczem i musimy stosowa(cid:202) go do pobierania elementów kolekcji. Jak ju(cid:285) podano, kolekcja SortedList jest po(cid:239)(cid:200)czeniem tablicy oraz tablicy mieszaj(cid:200)cej. Do jej elementów mo(cid:285)na si(cid:218) odwo(cid:239)ywa(cid:202) przy u(cid:285)yciu kluczy lub indeksów. W przypadku odwo(cid:239)ywania si(cid:218) przy u(cid:285)yciu indeksów dzia(cid:239)a ona jak ArrayList, natomiast w razie stosowania kluczy — jak Hashtable. Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Tabela 6.1. Klasy kolekcji (ci(cid:200)g dalszy) Klasa cd. Stack Queue BitArray Opis Oto sposób deklarowania kolekcji tego typu: SortedList sortedList = new SortedList(); Stos to kolekcja obiektów dzia(cid:239)aj(cid:200)ca zgodnie z zasad(cid:200) ostatni dodany, pierwszy obs(cid:239)u(cid:285)ony (ang. LIFO). Stosy obs(cid:239)uguj(cid:200) dwie podstawowe operacje: umieszczenie na stosie (Push) oraz zdj(cid:218)cie ze stosu (Pop). Pierwsza z tych operacji reprezentuje dodanie elementu na wierzcho(cid:239)ku stosu, natomiast druga — usuni(cid:218)cie elementu z wierzcho(cid:239)ka stosu. Oprócz tego mo(cid:285)na tak(cid:285)e odczyta(cid:202) element z wierzcho(cid:239)ka stosu bez jego usuwania (Peek). Stos mo(cid:285)na zadeklarowa(cid:202) w nast(cid:218)puj(cid:200)cy sposób: Stack stackList = new Stack(); Kolejka reprezentuje kolekcj(cid:218) obiektów dzia(cid:239)aj(cid:200)c(cid:200) zgodnie z zasad(cid:200) pierwszy dodany, pierwszy obs(cid:239)u(cid:285)ony (ang. FIFO). Kolejki obs(cid:239)uguj(cid:200) dwie podstawowe operacje: dodanie do kolejki (Enqueue) oraz usuni(cid:218)cie z niej (Dequeue). Poni(cid:285)ej przedstawiono sposób deklarowania kolekcji tego typu: Queue queue = new Queue(); BitArray to kolekcja reprezentuj(cid:200)ca tablic(cid:218) zarz(cid:200)dzaj(cid:200)c(cid:200) bitami. Poszczególne bity s(cid:200) reprezentowane jako warto(cid:258)ci logiczne. Logiczna prawda oznacza, (cid:285)e bit ma warto(cid:258)(cid:202) 1, a logiczny fa(cid:239)sz — (cid:285)e bit ma warto(cid:258)(cid:202) 0. Oto sposób deklarowania kolekcji tego typu: BitArray bitArray = new BitArray(8); Zastosowanie Jej najwa(cid:285)niejsz(cid:200) cech(cid:200) jest to, (cid:285)e zawarto(cid:258)(cid:202) takiej kolekcji pozostaje posortowana na podstawie kluczy. Kolekcje tego typu nale(cid:285)y stosowa(cid:202) w sytuacjach, kiedy ostatni element dodany do kolekcji ma by(cid:202) z niej usuni(cid:218)ty jako pierwszy. Kolekcje tego typu nale(cid:285)y stosowa(cid:202) w sytuacjach, kiedy element dodany do kolekcji jako pierwszy ma by(cid:202) z niej usuni(cid:218)ty jako pierwszy. Ta kolekcja przydaje si(cid:218) w sytuacjach, kiedy konieczne jest przechowywanie bitów. W tabeli 6.1 przedstawione zosta(cid:239)y wy(cid:239)(cid:200)cznie nieogólne klasy kolekcji. Dost(cid:218)pne s(cid:200) tak(cid:285)e klasy kolekcji zaimplementowane jako klasy ogólne; zosta(cid:239)y one umieszczone w przestrzeni nazw System.Collections. Kolekcje te zostan(cid:200) dok(cid:239)adniej przedstawione w dalszej cz(cid:218)(cid:258)ci rozdzia(cid:239)u. Wydajno(cid:258)(cid:202) — BitArray a tablica typu bool W zamieszczonej wcze(cid:258)niej tabeli 6.1 opisana zosta(cid:239)a klasa BitArray stanowi(cid:200)ca tablic(cid:218) s(cid:239)u(cid:285)(cid:200)c(cid:200) do zarz(cid:200)dzania warto(cid:258)ciami logicznymi (true, false) reprezentuj(cid:200)cymi bity (warto(cid:258)ci 0 lub 1). Jednak wewn(cid:218)trzny sposób dzia(cid:239)ania tej klasy opiera si(cid:218) na wykorzystaniu bajtów — grup o(cid:258)miu bitów — co wymaga wykonania ró(cid:285)nych operacji logicznych i zu(cid:285)ycia wi(cid:218)kszej liczby cykli procesora. Z drugiej strony zwyczajna tablica warto(cid:258)ci logicznych (bool[]) przechowuje 189 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego elementy jako bajty, dzi(cid:218)ki czemu zajmuje wi(cid:218)cej pami(cid:218)ci, lecz jednocze(cid:258)nie zu(cid:285)ywa mniej cykli procesora. Nale(cid:285)y zatem uzna(cid:202), (cid:285)e w stosunku do tablicy warto(cid:258)ci logicznych (bool[]) klasa BitArray jest zoptymalizowana pod k(cid:200)tem zu(cid:285)ycia pami(cid:218)ci. Przeanalizujmy poni(cid:285)szy test, który pozwoli nam okre(cid:258)li(cid:202) wydajno(cid:258)(cid:202) dzia(cid:239)ania kolekcji BitArray: private static long BitArrayTest(int max) { Stopwatch stopwatch = Stopwatch.StartNew(); var bitarray = new BitArray(max); for (int index = 0; index bitarray.Length; index++) { bitarray[index] = !bitarray[index]; WriteLine($ bitarray[{index}] = {bitarray[index]} ); } stopwatch.Stop(); return stopwatch.ElapsedMilliseconds; } Powy(cid:285)szy kod stanowi bardzo prosty test wydajno(cid:258)ci dzia(cid:239)ania klasy BitArray, w którym w p(cid:218)tli for ustawiamy liczb(cid:218) bitów odpowiadaj(cid:200)cych zakresowi typu int — int.MaxValue. Kolejny fragment kodu przedstawia analogiczny test sprawdzaj(cid:200)cy wydajno(cid:258)(cid:202) dzia(cid:239)ania tablicy bool[]; tak(cid:285)e w tym przypadku tekst operuje na tablicy wielko(cid:258)ci int.MaxValue. private static long BoolArrayTest(int max) { Stopwatch stopwatch = Stopwatch.StartNew(); var boolArray = new bool[max]; for (int index = 0; index boolArray.Length; index++) { boolArray[index] = !boolArray[index]; WriteLine($ boolArray[{index}] = {boolArray[index]} ); } stopwatch.Stop(); return stopwatch.ElapsedMilliseconds; } Kolejny fragment kodu pokazuje, w jaki sposób mo(cid:285)na wykona(cid:202) oba powy(cid:285)sze testy: private static void BitArrayBoolArrayPerformance() { // to prosty test; // nie sprawdza wydajno(cid:286)ci dzia(cid:225)ania operacji takich jak przesuni(cid:266)cia bitowe WriteLine( Porównanie wydajno(cid:258)ci BitArray oraz bool[].\n ); WriteLine($ Ca(cid:239)kowita liczba elementów: {int.MaxValue} ); PressAnyKey(); WriteLine( Testowanie kolekcji BitArray: ); var bitArrayTestResult = BitArrayTest(int.MaxValue); WriteLine( Test zako(cid:241)czony. ); 190 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych WriteLine( Czas: {0:hh\\:mm\\:ss} , TimeSpan.FromMilliseconds (cid:180)(bitArrayTestResult)); WriteLine( \nTestowanie tablicy bool[]: ); WriteLine($ Ca(cid:239)kowita liczba elementów: {int.MaxValue} ); PressAnyKey(); var boolArrayTestResult = BoolArrayTest(int.MaxValue); WriteLine( Test zako(cid:241)czony. ); a WriteLine( Czas: {0:hh\\:mm\\:ss} , TimeSpan.FromMilliseconds a (cid:180)(boolArrayTestResult)); } Na moim komputerze wykonanie metody BitArrayTest zaj(cid:218)(cid:239)o 6 sekund, a wykonanie metody BoolArrayTest — 15 sekund. Uzyskane wyniki wskazuj(cid:200), (cid:285)e klasa BitArray nie tylko zajmuje mniej miejsca w pami(cid:218)ci ni(cid:285) ta- blice bool[], lecz tak(cid:285)e zapewnia wi(cid:218)ksz(cid:200) wydajno(cid:258)(cid:202) dzia(cid:239)ania. Prezentacja typów ogólnych oraz ich zastosowania Najpro(cid:258)ciej rzecz ujmuj(cid:200)c, przy korzystaniu z typów ogólnych mo(cid:285)na napisa(cid:202) kod operuj(cid:200)cy na innym typie danych ni(cid:285) ten, z my(cid:258)l(cid:200) o którym by(cid:239) implementowany. Powiedzmy, (cid:285)e je(cid:258)li klasa ogólna by(cid:239)a pisana z my(cid:258)l(cid:200) o tym, (cid:285)e b(cid:218)dzie operowa(cid:202) na strukturze, to równie dobrze b(cid:218)dzie ona operowa(cid:202) na liczbach typu int, (cid:239)a(cid:241)cuchach znaków czy te(cid:285) dowolnych strukturach. Takie klasy s(cid:200) tak(cid:285)e nazywane klasami ogólnymi. Ich dzia(cid:239)anie staje si(cid:218) jeszcze bardziej magicz- ne, kiedy podczas tworzenia instancji klasy ogólnej mo(cid:285)na okre(cid:258)li(cid:202) typ danych, na jakich ma ona operowa(cid:202). Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad, przedstawiaj(cid:200)cy definicj(cid:218) zmiennej typu ogólnego wraz z okre(cid:258)lonym typem, na którym instancja ta ma dzia(cid:239)a(cid:202): IList Person persons = new List Person (); W powy(cid:285)szym przyk(cid:239)adzie zadeklarowali(cid:258)my zmienn(cid:200) persons, która jest kolekcj(cid:200) ogólnego typu List. Kolekcja ta podlega mechanizmom (cid:258)cis(cid:239)ej kontroli typów i ma operowa(cid:202) na obiektach klasy Person. Poni(cid:285)szy fragment kodu pokazuje, w jaki sposób mo(cid:285)na okre(cid:258)li(cid:202) zawarto(cid:258)(cid:202) kolekcji persons: private static IEnumerable Person CreatePersonList() { IList Person persons = new List Person { new Person { Id = 1, FirstName = Jan , LastName = Kowalski , Age = 31 }, 191 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego new Person { FirstName = Joanna , LastName = Tkaczyk , Age = 25 }, new Person { Id = 2, FirstName = Szymon , LastName = Wola(cid:241)ski , Age = 40 }, new Person { Id = 3, FirstName = Roman , LastName = Piotrowski , Age = 43 } }; return persons; } Powy(cid:298)szy fragment pokazuje sposób inicjalizacji kolekcji typu Person. Kolejny przyk(cid:225)ad pokazuje zapisanie elementów w kolekcji oraz wy(cid:286)wietlenie jej zawarto(cid:286)ci w p(cid:266)tli: private static void PersonList() { WriteLine( Lista osób: ); foreach (var person in Person.GetPersonList()) { WriteLine($ Personalia:{person.FirstName} {person.LastName} ); WriteLine($ Wiek:{person.Age} ); } ReadLine(); } Wyniki wykonania tej metody zosta(cid:239)y przedstawione na rysunku 6.1. Mo(cid:285)na tak(cid:285)e stworzy(cid:202) list(cid:218) ogóln(cid:200) korzystaj(cid:200)c(cid:200) z mechanizmu (cid:258)cis(cid:239)ej kontroli typów, która b(cid:218)dzie operowa(cid:202) na obiektach innych ni(cid:285) Person. Poni(cid:285)ej pokazano, jak to zrobi(cid:202): private IEnumerable T CreateGenericList T () { IList T persons = new List T (); // inny kod return persons; } 192 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Rysunek 6.1. Operacje na kolekcji typu ogólnego W tym przyk(cid:239)adzie T mo(cid:285)e by(cid:202) klas(cid:200) Person lub dowolnym innym typem. Kolekcje i typy ogólne W drugim dniu kursu wspominali(cid:258)my o tablicach — zbiorach danych, które maj(cid:200) (cid:258)ci(cid:258)le okre(cid:258)lon(cid:200) pojemno(cid:258)(cid:202). Mo(cid:285)na ich u(cid:285)ywa(cid:202) do przechowywania obiektów konkretnego typu i podlegaj(cid:200)cych mechanizmom (cid:258)cis(cid:239)ej kontroli typów. Co jednak zrobi(cid:202) w sytuacjach, kiedy chcieliby(cid:258)my zorgani- zowa(cid:202) dane przy wykorzystaniu innej struktury danych, takiej jak: kolejka, lista, stos itd.? W takim przypadku wystarczy zastosowa(cid:202) odpowiedni(cid:200) kolekcj(cid:218) (z przestrzeni nazw System.Collections). System.Collections (https://www.nuget.org/packages/System.Collections/) to pakiet NuGet zawie- raj(cid:200)cy typy ogólne, takie jak te przedstawione w tabeli 6.2. Tabela 6.2. Wybrane typy ogólne z przestrzeni nazw System.Collections Ogólny typ kolekcji Opis System.Collections.Generic.List T System.Collections.Generic.Dictionary TKey, TValue System.Collections.Generic.Queue T System.Collections.Generic.Stack T System.Collections.Generic.HashSet T System.Collections.Generic.LinkedList T System.Collections.Generic.SortedDictionary (cid:180) TKey, TValue Ogólna lista podlegaj(cid:200)ca (cid:258)cis(cid:239)ej kontroli typów. Ogólny s(cid:239)ownik par klucz – warto(cid:258)(cid:202) podlegaj(cid:200)cy (cid:258)cis(cid:239)ej kontroli typów. Ogólna klasa implementuj(cid:200)ca kolejk(cid:218). Ogólna klasa implementuj(cid:200)ca stos. Ogólna klasa HashSet. Ogólna klasa reprezentuj(cid:200)ca list(cid:218) po(cid:239)(cid:200)czon(cid:200). Ogólna klasa s(cid:239)ownika przechowuj(cid:200)ca pary klucz – warto(cid:258)(cid:202), sortowane na podstawie klucza. Powy(cid:285)sza tabela 6.2 zawiera jedynie niewielki fragment wszystkich klas dost(cid:218)pnych w przestrzeni nazw System.Collections.Generic. W dalszej cz(cid:218)(cid:258)ci rozdzia(cid:239)u klasy te zostan(cid:200) dok(cid:239)adniej opisane i przedstawione na przyk(cid:239)adach. 193 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Kompletn(cid:200) list(cid:218) klas, struktur oraz interfejsów dost(cid:218)pnych w przestrzeni nazw System.Collections. (cid:180)Generic mo(cid:285)na znale(cid:283)(cid:202) w jej oficjalnej dokumentacji, dost(cid:218)pnej na stronie https://docs.microsoft. com/en-us/dotnet/api/system.collections.generic?view=netcore-2.0. Dlaczego warto u(cid:285)ywa(cid:202) typów ogólnych? Uniwersalnym typem elementów kolekcji nieogólnych jest Object (https://docs.microsoft.com/ en-us/dotnet/api/system.object?view=netframework-4.7.1). Nie jest to rozwi(cid:200)zanie bezpieczne, gdy(cid:285) nie pozwala na kontrol(cid:218) typów podczas kompilacji kodu. Za(cid:239)ó(cid:285)my, (cid:285)e u(cid:285)ywamy nieogólnej kolekcji typu ArrayList; takiej jak ta przedstawiona na poni(cid:285)szym przyk(cid:239)adzie: ArrayList authorArrayList = new ArrayList { Jan Kowalski , 43 }; foreach (string author in authorArrayList) { WriteLine($ Personalia:{author} ); } Jak wida(cid:202), mamy tu do czynienia z kolekcj(cid:200) ArrayList zawieraj(cid:200)c(cid:200) (cid:239)a(cid:241)cuchy znaków. Tak(cid:285)e wiek osoby jest zapisywany w formie (cid:239)a(cid:241)cucha znaków, cho(cid:202) powinna to by(cid:202) warto(cid:258)(cid:202) typu int. Zmodyfikujmy zatem nasz(cid:200) list(cid:218) tak, by wiek faktycznie by(cid:239) przechowywany jako liczba ca(cid:239)kowita: ArrayList editorArrayList = new ArrayList { Joanna Tkaczyk , 25 }; foreach (int editor in editorArrayList) WriteLine($ {editor} ); Taki kod mo(cid:285)na prawid(cid:239)owo skompilowa(cid:202), jednak podczas próby jego wykonania zostanie zg(cid:239)oszony wyj(cid:200)tek zwi(cid:200)zany z b(cid:239)(cid:218)dem rzutowania (patrz rysunek 6.2). Oznacza to, (cid:285)e w przypadku stosowania klasy ArrayList nie jest przeprowadzana kontrola typów podczas kompilacji kodu: Rysunek 6.2. Wyj(cid:200)tek zg(cid:239)aszany podczas wykonywania ostatniego przyk(cid:239)adu 194 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Po przeanalizowaniu powy(cid:285)szego fragmentu kodu bez trudu mo(cid:285)na stwierdzi(cid:202), dlaczego podczas jego kompilacji nie zosta(cid:239) zg(cid:239)oszony (cid:285)aden wyj(cid:200)tek: klasa ArrayList akceptuje bowiem dowolny typ (zarówno warto(cid:258)ciowy, jak i referencyjny), a nast(cid:218)pnie rzutuje go do uniwersalnego typu platformy .NET, czyli Object. Jednak podczas wykonywania kodu kolekcja wymaga zastosowania konkretnego typu, na przyk(cid:239)ad je(cid:258)li zosta(cid:239)a zdefiniowana jako kolekcja (cid:239)a(cid:241)cuchów znaków, to nale(cid:285)y w niej zapisywa(cid:202) (cid:239)a(cid:241)cuchy znaków, a nie inne obiekty. W(cid:239)a(cid:258)nie dlatego podczas wykony- wania tego kodu zosta(cid:239) zg(cid:239)oszony wyj(cid:200)tek. Czynno(cid:258)ci zwi(cid:200)zane z rzutowaniem, pakowaniem oraz rozpakowywaniem wykonywane przez kolekcj(cid:218) ArrayList maj(cid:200) niekorzystny wp(cid:239)yw na wydajno(cid:258)(cid:202) dzia(cid:239)ania kodu — przy czym spadek efektywno(cid:258)ci jest zale(cid:285)ny od wielko(cid:258)ci kolekcji ArrayList oraz ilo(cid:258)ci przechowywanych w niej danych. Na podstawie powy(cid:285)szego przyk(cid:239)adu mo(cid:285)na wskaza(cid:202) podstawowe wady tej nieogólnej wersji klasy ArrayList: 1. Nie zapewnia kontroli typów podczas kompilacji kodu. 2. Ma negatywny wp(cid:239)yw na wydajno(cid:258)(cid:202) dzia(cid:239)ania w przypadku operowania na du(cid:285)ych zbiorach danych. 3. Wszystkie zapisywane w niej dane s(cid:200) rzutowane na Object, zatem nie mo(cid:285)na uniemo(cid:285)liwi(cid:202) dodawania do kolekcji obiektów innego typu ju(cid:285) w trakcie kompilacji kodu. Na przyk(cid:239)ad w poprzednim przyk(cid:239)adzie dodawali(cid:258)my do kolekcji (cid:239)a(cid:241)cuchy znaków i liczby ca(cid:239)kowite. Powy(cid:285)sze problemy mo(cid:285)na rozwi(cid:200)za(cid:202), stosuj(cid:200)c kolekcje b(cid:218)d(cid:200)ce typami ogólnymi, które uniemo(cid:285)- liwiaj(cid:200) dodawanie obiektów innego typu ni(cid:285) ten podany podczas ich tworzenia. Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad: List string authorName = new List string { Jan Kowalski }; Powy(cid:285)sza lista zosta(cid:239)a zdefiniowania w taki sposób, (cid:285)e mo(cid:285)na w niej zapisywa(cid:202) wy(cid:239)(cid:200)cznie ele- menty b(cid:218)d(cid:200)ce (cid:239)a(cid:241)cuchami znaków. A zatem mo(cid:285)na do niej dodawa(cid:202) wy(cid:239)(cid:200)cznie (cid:239)a(cid:241)cuchy znaków. Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad: List string authorName = new List string (); authorName.Add( Jan Kowalski ); authorName.Add(43); W tym przyk(cid:239)adzie próbujemy zapisa(cid:202) na li(cid:258)cie element typu int (Czytelnik zapewne pami(cid:218)ta, (cid:285)e w przypadku u(cid:285)ycia kolekcji ArrayList by(cid:239)o to mo(cid:285)liwe). Jednak w tym przypadku próba u(cid:285)ycia takiego kodu spowoduje zg(cid:239)oszenie b(cid:239)(cid:218)du rzutowania — a zatem lista ogólna zdefiniowana jako lista (cid:239)a(cid:241)cuchów znaków uniemo(cid:285)liwia dodawanie innych elementów ni(cid:285) (cid:239)a(cid:241)cuchy. Szcze- gó(cid:239)ow(cid:200) informacj(cid:218) o b(cid:239)(cid:218)dzie mo(cid:285)na wy(cid:258)wietli(cid:202), umieszczaj(cid:200)c wska(cid:283)nik myszy na liczbie 43, jak pokazano na rysunku 6.3. 195 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Rysunek 6.3. B(cid:239)(cid:200)d konwersji podczas dodawania elementu do listy ogólnej W powy(cid:285)szym przyk(cid:239)adzie rozwi(cid:200)zali(cid:258)my jeden z problemów — zadeklarowali(cid:258)my list(cid:218) (cid:239)a(cid:241)cu- chów znaków, dzi(cid:218)ki czemu mogli(cid:258)my na niej zapisywa(cid:202) wy(cid:239)(cid:200)cznie (cid:239)a(cid:241)cuchy znaków. Jednak w kontek(cid:258)cie przyk(cid:239)adu o autorach oznacza to, (cid:285)e mo(cid:285)emy na niej zapisywa(cid:202) wy(cid:239)(cid:200)cznie imi(cid:218) i nazwisko, lecz ju(cid:285) nie wiek autora. Mo(cid:285)na by si(cid:218) zastanawia(cid:202), po co u(cid:285)ywa(cid:202) kolekcji typu ogólnego, skoro w ich przypadku dodawanie nowego typu danych wymaga utworzenia nowej kolekcji? Obecnie potrzebujemy tylko dwóch informacji o autorze — personaliów oraz wieku; wystarczy(cid:239)oby zatem utworzy(cid:202) dwie listy: jedn(cid:200) typu string na personalia oraz drug(cid:200) typu int na wiek. Gdyby(cid:258)my jednak potrzebowali przechowywa(cid:202) jeszcze inne informacje, musieliby(cid:258)my w tym celu stworzy(cid:202) kolejn(cid:200) list(cid:218). Doprowadzi(cid:239)oby to do konieczno(cid:258)ci utworzenia wielu list ró(cid:285)nych typów, takich jak: string, int, decimal itd. Jednak zamiast tego mo(cid:285)na utworzy(cid:202) w(cid:239)asny, niestandardowy typ. Przyjrzyjmy si(cid:218) poni(cid:285)szej deklaracji listy: List Person persons = new List Person (); Jak wida(cid:202), tworzymy tu list(cid:218) obiektów typu Person. Ta ogólna lista pozwoli nam na zapisywanie na niej wy(cid:239)(cid:200)cznie obiektów podanego typu. A oto przyk(cid:239)adowa definicja klasy Person: internal class Person { public string FirstName { get; set; } public string LastName { get; set; } public int Age { get; set; } } Przedstawiona klasa Person definiuje trzy w(cid:239)a(cid:258)ciwo(cid:258)ci: dwie typu string oraz jedn(cid:200) typu int. W ten sposób znale(cid:283)li(cid:258)my rozwi(cid:200)zanie kolejnego z wcze(cid:258)niejszych problemów. Dzi(cid:218)ki stworze- niu kolekcji List o zawarto(cid:258)ci typu Person mo(cid:285)emy utworzy(cid:202) list(cid:218) i zapisywa(cid:202) w jej elementach informacje ró(cid:285)nych typów. Poni(cid:285)szy przyk(cid:239)ad przedstawia praktyczne zastosowanie takiej listy: private static void PersonList() { List Person persons = new List Person { new Person { 196 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych FirstName = Jan , LastName = Kowalski , Age = 43 } }; WriteLine( Lista osób: ); foreach (var person in persons) { WriteLine($ Personalia:{person.FirstName} {person.LastName} ); WriteLine($ Wiek:{person.Age} ); } } Wyniki wykonania tego przyk(cid:239)adu przedstawiono na rysunku 6.4. Rysunek 6.4. Wyniki zastosowania obiektów niestandardowego typu na li(cid:258)cie ogólnej Taka lista obiektów typu Person b(cid:218)dzie dzia(cid:239)a(cid:202) wydajniej ni(cid:285) kolekcja ArrayList, gdy(cid:285) jest list(cid:200) typu ogólnego, a zatem w jej przypadku nie b(cid:218)d(cid:200) wykonywane (cid:285)adne operacje rzutowania do typu Object — jej zawarto(cid:258)ci(cid:200) b(cid:218)d(cid:200) obiekty wy(cid:239)(cid:200)cznie okre(cid:258)lonego typu. Stosowanie ogranicze(cid:241) typów ogólnych W poprzednim podpunkcie rozdzia(cid:239)u przedstawiona zosta(cid:239)a kolekcja List typu Person, akcep- tuj(cid:200)ca obiekty typu okre(cid:258)lonego w definicji. W przedstawionym kodzie obiekty te zawiera(cid:239)y jedynie dane typu string i int, jednak ogólnie nic nie stoi na przeszkodzie, by u(cid:285)ywa(cid:202) tak(cid:285)e innych typów danych, takich jak warto(cid:258)ci typów float, double itd. Z drugiej strony mog(cid:200) si(cid:218) tak(cid:285)e pojawia(cid:202) sytuacje, w których b(cid:218)dziemy chcieli ograniczy(cid:202) stosowane typy danych lub umo(cid:285)liwi(cid:202) stosowanie w typie ogólnym w ogóle tylko jednego, (cid:258)ci(cid:258)le okre(cid:258)lonego typu. W(cid:239)a(cid:258)nie z my(cid:258)l(cid:200) o takich sytuacjach w j(cid:218)zyku C# wprowadzono ograniczenia typów ogólnych. Przeanali- zujmy nast(cid:218)puj(cid:200)cy przyk(cid:239)ad: public class GenericConstraint T where T:class { public T ImplementIt(T value) { return value; } } 197 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Klasa przedstawiona na tym przyk(cid:239)adzie jest klas(cid:200) ogóln(cid:200). Zastosowany w niej ogólny typ T jest niczym innym jak dowolnym typem referencyjnym; oznacza to, (cid:285)e tworz(cid:200)c instancj(cid:218) klasy GenericConstraint, mo(cid:285)emy za(cid:285)(cid:200)da(cid:202), by operowa(cid:239)a ona na dowolnym typie referencyjnym. Jednak w takiej klasie nie b(cid:218)dzie mo(cid:285)na u(cid:285)ywa(cid:202) (cid:285)adnych typów warto(cid:258)ciowych. Nasza klasa definiuje metod(cid:218) ImplementIt, która akceptuje parametr typu T i zwraca warto(cid:258)(cid:202) typu T. Wi(cid:218)cej informacji na temat wytycznych dotycz(cid:200)cych okre(cid:258)lania parametrów typów mo(cid:285)na znale(cid:283)(cid:202) na stronie https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic-type-parameters. Poni(cid:285)sze deklaracje s(cid:200) prawid(cid:239)owe, gdy(cid:285) zastosowano w nich typy referencyjne: GenericConstraint string genericConstraint = new GenericConstraint string (); Person person = genericPersonConstraint.ImplementIt(new Person()); Z kolei poni(cid:285)sza deklaracja nie jest prawid(cid:239)owa, gdy(cid:285) u(cid:285)yto w niej typu warto(cid:258)ciowego, a definicja klasy GenericConstraint na to nie pozwala: GenericConstraint int genericConstraint = new GenericConstraint int (); W drugim dniu kursu dowiedzieli(cid:258)my si(cid:218), (cid:285)e int jest typem warto(cid:258)ciowym, a nie referencyjnym. Dlatego te(cid:285) próba zastosowania takiej deklaracji spowoduje zg(cid:239)oszenie b(cid:239)(cid:218)du czasu kompilacji. B(cid:239)(cid:200)d ten jest wy(cid:258)wietlany w Visual Studio w sposób przedstawiony na rysunku 6.5. Rysunek 6.5. B(cid:239)(cid:200)d zwi(cid:200)zany z naruszeniem ograniczenia typu ogólnego A zatem dzi(cid:218)ki zastosowaniu ograniczenia typu ogólnego uniemo(cid:285)liwili(cid:258)my zastosowanie innego typu ni(cid:285) referencyjny. Ograniczenia mo(cid:285)na by w zasadzie uzna(cid:202) za zabezpieczenie naszej klasy ogólnej przed stosowaniem nieodpowiednich typów podczas tworzenia instancji naszego typu ogólnego. Je(cid:258)li klient spróbuje zastosowa(cid:202) nieodpowiedni typ, spowoduje to zg(cid:239)oszenie b(cid:239)(cid:218)du czasu kompilacji. Do definiowania tych ogranicze(cid:241) u(cid:285)ywane jest kontekstowe s(cid:239)owo kluczowe where. W rzeczywisto(cid:258)ci mo(cid:285)liwe jest definiowanie ró(cid:285)nego rodzaju ogranicze(cid:241), dzi(cid:218)ki którym mo(cid:285)na za- bezpiecza(cid:202) klasy ogólne przed niepo(cid:285)(cid:200)danymi sytuacjami. Przeanalizujmy kilka takich przypadków: 198 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Typy warto(cid:258)ciowe To pierwsze ograniczenie zostanie zdefiniowanie przy u(cid:285)yciu zapisu: where T: struct. W tym przypadku kod klienta, okre(cid:258)laj(cid:200)c typ klasy ogólnej, powinien zastosowa(cid:202) typ warto(cid:258)ciowy — mo(cid:285)e to by(cid:202) dowolny typ warto(cid:258)ciowy z wyj(cid:200)tkiem typów akceptuj(cid:200)cych warto(cid:258)(cid:202) null. Przyk(cid:239)ad Oto przyk(cid:239)ad deklaracji klasy zawieraj(cid:200)cej ograniczenie typu warto(cid:258)ciowego: public class ValueTypeConstraint T where T : struct { public T ImplementIt(T value) { return value; } } Zastosowanie Poni(cid:285)szy fragment pokazuje przyk(cid:239)ad kodu klienta, w którym zastosowano klas(cid:218) ogóln(cid:200) z ograni- czeniem typu warto(cid:258)ciowego: private static void ImplementValueTypeGenericClass() { const int age = 43; ValueTypeConstraint int valueTypeConstraint = new ValueTypeConstraint int (); WriteLine($ Wiek:{valueTypeConstraint.ImplementIt(age)} ); } Typy referencyjne Takie ograniczenie mo(cid:285)na zdefiniowa(cid:202), u(cid:285)ywaj(cid:200)c zapisu o postaci: where T:class. W razie zasto- sowania takiego ograniczenia kod klienta, tworz(cid:200)c instancje typu ogólnego, mo(cid:285)e zastosowa(cid:202) w niej dowolny typ referencyjny — mo(cid:285)e to by(cid:202) dowolna klasa, interfejs, delegacja czy te(cid:285) tablica. Przyk(cid:239)ad Poni(cid:285)szy przyk(cid:239)ad przedstawia deklaracj(cid:218) klasy ogólnej z ograniczeniem typu referencyjnego: public class ReferenceTypeConstraint T where T:class { public T ImplementIt(T value) { return value; } } 199 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Zastosowanie Poni(cid:285)szy przyk(cid:239)ad przedstawia kod klienta, w którym zastosowano klas(cid:218) ogóln(cid:200) z ograniczeniem typu referencyjnego: private static void ImplementReferenceTypeGenericClass() { const string thisIsAuthorName = Jan Kowalski ; ReferenceTypeConstraint string referenceTypeConstraint = new (cid:180)ReferenceTypeConstraint string (); WriteLine($ Personalia:{referenceTypeConstraint.ImplementIt(thisIsAuthorName)} ); ReferenceTypeConstraint Person referenceTypePersonConstraint = new (cid:180)ReferenceTypeConstraint Person (); Person person = referenceTypePersonConstraint.ImplementIt(new Person { FirstName = Jan , LastName = Kowalski , Age = 43 }); WriteLine($ Personalia:{person.FirstName}{person.LastName} ); WriteLine($ Wiek:{person.Age} ); } Domy(cid:258)lny konstruktor To ograniczenie jest definiowane przy u(cid:285)yciu zapisu o postaci: where T: new(). Sprawia ono, (cid:285)e parametrem typu nie mo(cid:285)e by(cid:202) typ definiuj(cid:200)cy konstruktor domy(cid:258)lny. Jednocze(cid:258)nie narzuca ono wymóg, by typ T definiowa(cid:239) publiczny konstruktor bezargumentowy. W razie stosowania z innymi ograniczeniami, ograniczenie new() nale(cid:285)y podawa(cid:202) jako ostatnie. Przyk(cid:239)ad Poni(cid:285)szy przyk(cid:239)ad przedstawia deklaracj(cid:218) klasy ogólnej z ograniczeniem konstruktora domy(cid:258)lnego: public class DefaultConstructorConstraint T where T : new() { public T ImplementIt(T value) { return value; } } Zastosowanie Kolejny przyk(cid:239)ad przedstawia kod klienta, w którym zastosowano klas(cid:218) ogóln(cid:200) z ograniczeniem konstruktora domy(cid:258)lnego: 200 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych private static void ImplementDefaultConstructorGenericClass() { DefaultConstructorConstraint ClassWithDefaultConstructor (cid:180)constructorConstraint = new DefaultConstructorConstraint ClassWithDefaultConstructor (); var result = constructorConstraint.ImplementIt(new ClassWithDefaultConstructor (cid:180){ Name = Jan Kowalski }); WriteLine($ Personalia:{result.Name} ); } Ograniczenie klasy bazowej Ograniczenie klasy bazowej mo(cid:285)na zdefiniowa(cid:202), u(cid:285)ywaj(cid:200)c nast(cid:218)puj(cid:200)cego zapisu: where T: KlasaBazowa . To ograniczenie uniemo(cid:285)liwia zastosowanie jako parametru typu klasy innej ni(cid:285) dziedzicz(cid:200)ca po okre(cid:258)lonej klasie bazowej. Przyk(cid:239)ad Oto przyk(cid:239)ad deklaracji klasy ogólnej wykorzystuj(cid:200)cej ograniczenie klasy bazowej: public class BaseClassConstraint T where T:Person { public T ImplementIt(T value) { return value; } } Zastosowanie Poni(cid:285)szy fragment kodu przedstawia przyk(cid:239)ad zastosowania klasy ogólnej z ograniczeniem klasy bazowej: private static void ImplementBaseClassConstraint() { BaseClassConstraint Author baseClassConstraint = new (cid:180)BaseClassConstraint Author (); var result = baseClassConstraint.ImplementIt(new Author { FirstName = Shivprasad , LastName = Koirala , Age = 40 }); WriteLine($ Personalia:{result.FirstName} {result.LastName} ); WriteLine($ Wiek:{result.Age} ); } 201 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Ograniczenie interfejsu Ten rodzaj ograniczenia mo(cid:285)na zdefiniowa(cid:202), u(cid:285)ywaj(cid:200)c nast(cid:218)puj(cid:200)cego zapisu: where T: nazwa_ (cid:180)interfejsu . W tym przypadku, tworz(cid:200)c instancj(cid:218) klasy ogólnej, kod klienta musi zastosowa(cid:202) typ implementuj(cid:200)cy podany interfejs. Wskazany typ mo(cid:285)e implementowa(cid:202) dowolnie wiele interfejsów. Przyk(cid:239)ad Oto przyk(cid:239)ad deklaracji klasy korzystaj(cid:200)cej z ograniczenia typu interfejsu: public class InterfaceConstraint T :IDisposable where T : IDisposable { public T ImplementIt(T value) { return value; } public void Dispose() { // czynno(cid:286)ci porz(cid:261)dkowe } } Zastosowanie Poni(cid:285)szy fragment kodu przedstawia kod klienta, w którym zastosowano klas(cid:218) ogóln(cid:200) z ogranicze- niem typu interfejsu: private static void ImplementInterfaceConstraint() { InterfaceConstraint EntityClass entityConstraint = new (cid:180)InterfaceConstraint EntityClass (); var result=entityConstraint.ImplementIt(new EntityClass (cid:180){Name = Jan Kowalski }); WriteLine($ Personalia:{result.Name} ); } W tym podrozdziale przedstawione zosta(cid:239)y kolekcje oraz typy ogólne, jak równie(cid:285) ró(cid:285)ne rodzaje ogranicze(cid:241) typów ogólnych. Oprócz tego wyja(cid:258)nili(cid:258)my, dlaczego nale(cid:285)y stosowa(cid:202) typy ogólne. Wi(cid:218)cej szczegó(cid:239)owych informacji na temat typów ogólnych mo(cid:285)na znale(cid:283)(cid:202) w oficjalnej dokumentacji j(cid:218)zyka C# dost(cid:218)pnej na stronie https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/generic- -type-parameters. 202 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Upi(cid:218)kszanie kodu przy u(cid:285)yciu atrybutów Atrybuty zapewniaj(cid:200) mo(cid:285)liwo(cid:258)(cid:202) kojarzenia informacji z kodem. Informacje te mog(cid:200) mie(cid:202) posta(cid:202) prostych komentarzy lub ostrze(cid:285)e(cid:241), lecz mog(cid:200) tak(cid:285)e zawiera(cid:202) z(cid:239)o(cid:285)one operacje, a nawet kod. Atrybuty s(cid:200) definiowane przy u(cid:285)yciu znaczników. Rozwi(cid:200)zanie to pozwala tak(cid:285)e na upi(cid:218)kszanie kodu poprzez dodawanie do niego niestandardowych atrybutów. Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad: private void PeerOperation() { // inny kod WriteLine( Uko(cid:241)czono poziom 1. ); // inny kod } W powy(cid:285)szej metodzie wy(cid:258)wietlamy komunikat tekstowy stanowi(cid:200)cy informacj(cid:218) dla u(cid:285)ytkownika. Kolejny fragment kodu pokazuje, jak mo(cid:285)na doda(cid:202) do metody atrybut. Oto przyk(cid:239)ad: [PeerInformation( Uko(cid:241)czono poziom. )] private void PeerOperation() { // inny kod } W tym przyk(cid:239)adzie dodali(cid:258)my do metody jedynie atrybut z informacj(cid:200) tekstow(cid:200). Zgodnie z oficjaln(cid:200) dokumentacj(cid:200) (dost(cid:218)pn(cid:200) na stronie https://docs.microsoft.com/en-us/dotnet/ csharp/tutorials/attributes) atrybuty zapewniaj(cid:200) sposób deklaratywnego kojarzenia informacji z kodem. Mog(cid:200) tak(cid:285)e tworzy(cid:202) elementy wielokrotnego u(cid:285)ycia, które mo(cid:285)na dodawa(cid:202) do wielu ró(cid:285)nych elementów docelowych. Atrybutów mo(cid:285)na u(cid:285)ywa(cid:202) do: (cid:81) dodawania metadanych do kodu; (cid:81) dodawania do kodu komentarzy, opisów, instrukcji dla kompilatora i tak dalej. W kolejnych punktach rozdzia(cid:239)u zostan(cid:200) szczegó(cid:239)owo opisane atrybuty oraz przedstawione przyk(cid:239)ady ich zastosowania. Typy atrybutów W poprzednim punkcie rozdzia(cid:239)u przedstawione zosta(cid:239)y atrybuty, których mo(cid:285)na u(cid:285)ywa(cid:202) do upi(cid:218)kszania oraz dodawania informacji do kodu. W tym punkcie zaprezentowane zostan(cid:200) ró(cid:285)ne typy atrybutów. 203 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego AttributeUsage To predefiniowany atrybut frameworka .NET. S(cid:239)u(cid:285)y on do ograniczania zastosowania innych atrybutów. Oznacza to, (cid:285)e pozwala okre(cid:258)li(cid:202) rodzaje elementów, do jakich mo(cid:285)na dodawa(cid:202) dany atrybut; takie elementy s(cid:200) tak(cid:285)e nazywane elementami docelowymi atrybutów. Poni(cid:285)ej przedsta- wiona zosta(cid:239)a lista takich elementów docelowych: (cid:81) Assembly, (cid:81) Class, (cid:81) Constructor, (cid:81) Delegate, (cid:81) Enum, (cid:81) Event, (cid:81) Field, (cid:81) GenericParameter, (cid:81) Interface, (cid:81) Method, (cid:81) Module, (cid:81) Parameter, (cid:81) Property, (cid:81) ReturnValue, (cid:81) Struct. Domy(cid:258)lnie typ elementu docelowego atrybutu mo(cid:285)e by(cid:202) dowolny, chyba (cid:285)e zostanie on jawnie okre(cid:258)lony. Przyk(cid:239)ad Poni(cid:285)szy atrybut mo(cid:285)e by(cid:202) dodawany wy(cid:239)(cid:200)cznie do klas: [AttributeUsage(AttributeTargets.Class)] public class PeerInformationAttribute : Attribute { public PeerInformationAttribute(string information) { WriteLine(information); } } W powy(cid:285)szym przyk(cid:239)adzie zdefiniowali(cid:258)my atrybut przeznaczony do stosowania w klasach. Je(cid:258)li spróbujemy doda(cid:202) go do innego elementu docelowego ni(cid:285) klasa, spowoduje to wyst(cid:200)pienie b(cid:239)(cid:218)du kompilacji, takiego jak ten przedstawiony na rysunku 6.6, informuj(cid:200)cego, (cid:285)e atrybut przeznaczony do u(cid:285)ycia w deklaracjach klas zosta(cid:239) u(cid:285)yty w metodzie. 204 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Rysunek 6.6. Komunikat o dodaniu atrybutu do nieprawid(cid:239)owego elementu docelowego Obsolete Czasami mog(cid:200) si(cid:218) pojawi(cid:202) sytuacje, kiedy b(cid:218)dziemy chcieli wygenerowa(cid:202) ostrze(cid:285)enie w razie zastosowania okre(cid:258)lonego kodu. W(cid:239)a(cid:258)nie do tego celu s(cid:239)u(cid:285)y predefiniowany atrybut Obsolete. Przyk(cid:239)ad Przeanalizujmy poni(cid:285)szy kod, w którym deklaracja klasy zosta(cid:239)a poprzedzona atrybutem Obsolete. Poni(cid:285)szy kod mo(cid:285)na z powodzeniem skompilowa(cid:202) i uruchomi(cid:202), nawet pomimo wy(cid:258)wietlenia ostrze(cid:285)enia, gdy(cid:285) nie za(cid:285)(cid:200)dali(cid:258)my generowania b(cid:239)(cid:218)du: [Obsolete( Prosz(cid:218) nie u(cid:285)ywa(cid:202) tej klasy, zamiast niej nale(cid:285)y u(cid:285)y(cid:202) (cid:180)klasy Person . )] public class Author:Person { // inny kod } Rysunek 6.7 przedstawia komunikat informuj(cid:200)cy, (cid:285)e nie nale(cid:285)y u(cid:285)ywa(cid:202) klasy Author, gdy(cid:285) zosta(cid:239)a ona uznana za przestarza(cid:239)(cid:200). Pomimo komunikatu taki kod wci(cid:200)(cid:285) mo(cid:285)na skompilowa(cid:202) i uruchomi(cid:202) (nie za(cid:285)(cid:200)dali(cid:258)my bowiem, by ostrze(cid:285)enie by(cid:239)o traktowane jako b(cid:239)(cid:200)d). Rysunek 6.7. Komunikat ostrzegawczy generowany dzi(cid:218)ki zastosowaniu atrybutu Obsolete Z kolei zastosowanie atrybutu o nast(cid:218)puj(cid:200)cej postaci spowoduje nie tylko wy(cid:258)wietlenie ostrze- (cid:285)enia, lecz tak(cid:285)e wygenerowanie b(cid:239)(cid:218)du: [Obsolete( Prosz(cid:218) nie u(cid:285)ywa(cid:202) tej klasy, zamiast niej nale(cid:285)y u(cid:285)y(cid:202) (cid:180)klasy Person . ,true)] 205 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego public class Author:Person { // inny kod } Poni(cid:285)szy rysunek pokazuje, (cid:285)e zastosowanie takiego atrybutu powoduje wygenerowanie wyj(cid:200)tku. Rysunek 6.8. Zastosowanie atrybutu Obsolete do generowania b(cid:239)(cid:218)du Conditional Kolejny z predefiniowanych atrybutów, Conditional, ogranicza wykonanie na podstawie warunku umieszczonego w kodzie. Przyk(cid:239)ad Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad, który uzale(cid:285)nia mo(cid:285)liwo(cid:258)(cid:202) wykonania metody od zastosowania dyrektywy Debug preprocesora (zagadnienia zwi(cid:200)zane z preprocesorem oraz jego dyrektywami zostan(cid:200) opisane w dalszej cz(cid:218)(cid:258)ci rozdzia(cid:239)u): #define Debug using System.Diagnostics; using static System.Console; namespace Dzien06 { internal class Program { private static void Main(string[] args) { PersonList(); ReadLine(); } [Conditional( Debug )] private static void PersonList() 206 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych { WriteLine( Lista osób: ); foreach (var person in Person.GetPersonList()) { WriteLine($ Personalia:{person.FirstName} {person.LastName} ); WriteLine($ Wiek:{person.Age} ); } } } } Definiuj(cid:200)c dyrektywy preprocesora, trzeba pami(cid:218)ta(cid:202) o jednej rzeczy: konieczne jest zapisywanie ich na samym pocz(cid:200)tku pliku. Tworzenie i stosowanie niestandardowych atrybutów W poprzednim punkcie rozdzia(cid:239)u zosta(cid:239)y przedstawione predefiniowane atrybuty; wspomniano tak(cid:285)e, (cid:285)e ich mo(cid:285)liwo(cid:258)ci s(cid:200) raczej ograniczone, a w praktycznych zastosowaniach konieczne b(cid:218)dzie u(cid:285)ywanie znacznie bardziej z(cid:239)o(cid:285)onych atrybutów. W takich przypadkach mo(cid:285)e si(cid:218) przyda(cid:202) mo(cid:285)liwo(cid:258)(cid:202) tworzenia w(cid:239)asnych, niestandardowych atrybutów — przypominaj(cid:200) one atrybuty predefiniowane, jednak to ich twórca okre(cid:258)la sposób dzia(cid:239)ania takich atrybutów oraz typy ich elementów docelowych. Wszystkie niestandardowe atrybuty nale(cid:285)y definiowa(cid:202) jako klasy dziedzicz(cid:200)ce po klasie System.Attribute. W tym punkcie rozdzia(cid:239)u zaimplementujemy niestandardowy atrybut spe(cid:239)niaj(cid:200)cy nast(cid:218)puj(cid:200)ce za(cid:239)o(cid:285)enia: (cid:81) Atrybut b(cid:218)dzie nosi(cid:202) nazw(cid:218) ErrorLogger. (cid:81) Atrybut b(cid:218)dzie dzia(cid:239)a(cid:239) we wszystkich dost(cid:218)pnych (cid:258)rodowiskach: do debugowania, do tworzenia kodu, produkcyjnym itd. (cid:81) Zastosowanie atrybutu b(cid:218)dzie si(cid:218) ogranicza(cid:239)o jedynie do metod. (cid:81) Atrybut powinien powodowa(cid:202) wy(cid:258)wietlanie niestandardowych lub podanych komunikatów o b(cid:239)(cid:218)dach. (cid:81) Domy(cid:258)lnie atrybut powinien dzia(cid:239)a(cid:202) w (cid:258)rodowisku Debug. (cid:81) W razie zastosowania w (cid:258)rodowisku do tworzenia kodu oraz (cid:258)rodowisku Debug atrybut powinien wy(cid:258)wietla(cid:202) komunikat i zg(cid:239)asza(cid:202) wyj(cid:200)tek. Wymagania wst(cid:218)pne Do tworzenia i stosowania niestandardowych atrybutów b(cid:218)dziemy potrzebowa(cid:202): (cid:81) Visual Studio 2017 lub nowszego; (cid:81) .NET Core 1.1 lub nowszego. Poni(cid:285)ej przedstawiony zosta(cid:239) kod niestandardowego atrybutu spe(cid:239)niaj(cid:200)cego opisane wcze(cid:258)niej za(cid:239)o(cid:285)enia: 207 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego public class ErrorLogger : Attribute { public ErrorLogger(string exception) { switch (Env) { case Env.Debug: case Env.Dev: WriteLine($ {exception} ); throw new Exception(exception); case Env.Prod: WriteLine($ {exception} ); break; default: WriteLine($ {exception} ); throw new Exception(exception); } } public Env Env { get; set; } } Dzia(cid:239)anie powy(cid:285)szego atrybutu sprowadza si(cid:218) do wy(cid:258)wietlenia w oknie konsoli wyj(cid:200)tków poda- nych w kodzie, w którym atrybut zosta(cid:239) u(cid:285)yty. W przypadku (cid:258)rodowisk Debug oraz Dev oprócz wy(cid:258)wietlenia komunikatu zostanie tak(cid:285)e zg(cid:239)oszony wyj(cid:200)tek. Kolejny fragment kodu przedstawia proste przyk(cid:239)ady zastosowania tego atrybutu: public class MathClass { [ErrorLogger( Operacja Add jest w trakcie implementacji! , Env = Env.Debug)] public string Add(int num1, int num2) { return $ Suma liczb {num1} oraz {num2} wynosi: {num1 + num2} ; } [ErrorLogger( Operacja Subtract jest w trakcie implementacji! , Env = Env.Dev)] public string Subtract(int num1, int num2) { return $ Ró(cid:285)nica liczb {num1} i {num2} wynosi: {num1 - num2} ; } [ErrorLogger( Operacja Multiply jest w trakcie implementacji! , Env = Env.Prod)] public string Multiply(int num1, int num2) { return $ Iloczyn liczb {num1} i {num2} wynosi: {num1 * num2} ; } } 208 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych W powy(cid:285)szym przyk(cid:239)adzie zosta(cid:239)y zdefiniowane ró(cid:285)ne metody opatrzone atrybutami, które zostan(cid:200) zastosowane w ró(cid:285)nych (cid:258)rodowiskach. Atrybuty te spowoduj(cid:200) wy(cid:258)wietlenie komunikatu i zg(cid:239)osze- nie wyj(cid:200)tku podczas próby u(cid:285)ycia poszczególnych metod. Stosowanie dyrektyw preprocesora Dyrektywy preprocesora, jak wskazuje ich nazwa, s(cid:200) przetwarzane przed rozpocz(cid:218)ciem procesu kompilacji kodu. Innymi s(cid:239)owy, preprocesor przekazuje kompilatorowi instrukcje dotycz(cid:200)ce przetwarzania informacji, przy czym nast(cid:218)puje to przed skompilowaniem kodu przez kompilator. Wa(cid:285)ne zagadnienia Poni(cid:285)ej przedstawionych zosta(cid:239)o kilka wa(cid:285)nych uwag zwi(cid:200)zanych ze stosowaniem preprocesora: (cid:81) Dyrektywy preprocesora s(cid:200) w rzeczywisto(cid:258)ci warunkami uwzgl(cid:218)dnianymi przez kompilator. (cid:81) Dyrektywy preprocesora musz(cid:200) zaczyna(cid:202) si(cid:218) od znaku #. (cid:81) W odró(cid:285)nieniu od instrukcji dyrektyw preprocesora nie nale(cid:285)y ko(cid:241)czy(cid:202) (cid:258)rednikiem (;). (cid:81) Preprocesor nie jest u(cid:285)ywany do tworzenia i stosowania makr. (cid:81) Poszczególne dyrektywy preprocesora nale(cid:285)y deklarowa(cid:202) w odr(cid:218)bnych wierszach. Dyrektywy preprocesora w dzia(cid:239)aniu Przeanalizujmy poni(cid:285)szy przyk(cid:239)ad: #if ... #endif Przedstawia on warunkow(cid:200) dyrektyw(cid:218) preprocesora; blok kodu umieszczony wewn(cid:200)trz niej zostanie przetworzony, je(cid:258)li b(cid:218)dzie spe(cid:239)niony warunek okre(cid:258)lony w dyrektywie. Powy(cid:285)sz(cid:200) par(cid:218) dyrektyw mo(cid:285)na uzupe(cid:239)ni(cid:202) dyrektywami #elseif oraz #else. Poniewa(cid:285) jest to dyrektywa warun- kowa, a warunki logiczne w j(cid:218)zyku C# zwracaj(cid:200) wynik typu Boolean, to w warunkach po- dawanych w tych dyrektywach mo(cid:285)na u(cid:285)ywa(cid:202) operatorów logicznych, takich jak: równy (==), ró(cid:285)ny (!=), koniunkcja logiczna ( ), alternatywa logiczna (||) oraz negacja (!). Symbole preprocesora nale(cid:285)y definiowa(cid:202) na samym pocz(cid:200)tku pliku, w którym b(cid:218)d(cid:200) stosowane, u(cid:285)ywaj(cid:200)c do tego celu dyrektywy #define. Przeanalizujmy poni(cid:285)szy fragment kodu, który informuje u(cid:285)ytkownika o kompilacji warunkowej: #define DEBUG #define DEV using static System.Console; 209 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego namespace Dzien06 { public class PreprocessorDirective { public void ConditionalProcessor() = #if (DEBUG !DEV) WriteLine( Zdefiniowano symbol DEBUG. ); #elif (!DEBUG DEV) WriteLine( Zdefiniowano symbol DEV ); #else WriteLine( Zdefiniowano symbole DEBUG i DEV ); #endif } } W powy(cid:285)szym przyk(cid:239)adzie zdefiniowali(cid:258)my dwa ró(cid:285)ne symbole — DEBUG i DEV — dla dwóch ró(cid:285)nych (cid:258)rodowisk kompilacji. Ze wzgl(cid:218)du na zastosowane dyrektywy preprocesora wykonanie powy(cid:285)szego przyk(cid:239)adu spowoduje wy(cid:258)wietlenie wyników przedstawionych na rysunku 6.9. Rysunek 6.9. Efekty zastosowania dyrektyw preprocesora Dyrektywy #define i #undef Najpro(cid:258)ciej rzecz ujmuj(cid:200)c, dyrektywa #define definiuje symbol, który nast(cid:218)pnie mo(cid:285)e by(cid:202) u(cid:285)y- wany w warunkowych dyrektywach preprocesora. Dyrektywy #define nie mo(cid:285)na u(cid:285)ywa(cid:202) do deklarowania sta(cid:239)ych. Przy stosowaniu tej dyrektywy nale(cid:285)y pami(cid:218)ta(cid:202) o nast(cid:218)puj(cid:200)cych zagadnieniach: (cid:81) Dyrektywy #define nie mo(cid:285)na u(cid:285)ywa(cid:202) do deklarowania sta(cid:239)ych. (cid:81) Dyrektywa ta pozwala zdefiniowa(cid:202) symbol, lecz nie pozwala przypisywa(cid:202) mu warto(cid:258)ci. (cid:81) Symbol preprocesora mo(cid:285)e by(cid:202) u(cid:285)ywany wy(cid:239)(cid:200)cznie po jego uprzednim zdefiniowaniu; oznacza to, (cid:285)e dyrektyw(cid:218) #define nale(cid:285)y umieszcza(cid:202) na samym pocz(cid:200)tku pliku. (cid:81) Zasi(cid:218)g symbolu obejmuje ca(cid:239)y plik (cid:283)ród(cid:239)owy, w którym dany symbol zosta(cid:239) zdefiniowany. Wró(cid:202)my teraz do przyk(cid:239)adu prezentuj(cid:200)cego zastosowanie warunkowej dyrektywy #if, na którego pocz(cid:200)tku zosta(cid:239)y zdefiniowane dwa symbole preprocesora. Zdefiniowa(cid:202) taki symbol mo(cid:285)na bardzo (cid:239)atwo, na przyk(cid:239)ad: #define DEBUG. 210 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych Istnieje tak(cid:285)e mo(cid:285)liwo(cid:258)(cid:202) usuni(cid:218)cia zdefiniowanego wcze(cid:258)niej symbolu; s(cid:239)u(cid:285)y do tego dyrektywa preprocesora #undef. Przeanalizujmy kolejny przyk(cid:239)ad: #define DEBUG #define DEV #undef DEBUG using static System.Console; namespace Dzien06 { public class PreprocessorDirective { public void ConditionalProcessor() = #if (DEBUG !DEV) WriteLine( Zdefiniowano symbol DEBUG. ); #elif (!DEBUG DEV) WriteLine( Zdefiniowano symbol DEV ); #else WriteLine( Zdefiniowano symbole DEBUG i DEV ); #endif } } W tym przyk(cid:239)adzie najpierw definiujemy, a nast(cid:218)pnie usuwamy symbol DEBUG; oznacza to, (cid:285)e wy- konanie powy(cid:285)szego przyk(cid:239)adu wygeneruje wyniki przedstawione na rysunku 6.10. Rysunek 6.10. Efekty zastosowania dyrektywy preprocesora #undef Dyrektywy #region oraz #endregion Dyrektywy #region oraz #endregion s(cid:200) niezwykle przydatne podczas pracy nad d(cid:239)ugimi plikami (cid:283)ród(cid:239)owymi. Czasami podczas prac nad du(cid:285)ymi aplikacjami, na przyk(cid:239)ad korporacyjnymi, pliki (cid:283)ród(cid:239)owe mog(cid:200) przekracza(cid:202) nawet 1000 wierszy kodu, obejmuj(cid:200)cego przeró(cid:285)ne funkcje, metody czy te(cid:285) logik(cid:218) biznesow(cid:200). Dla poprawy przejrzysto(cid:258)ci mo(cid:285)na podzieli(cid:202) taki kod na regiony. Dla ka(cid:285)dego regionu mo(cid:285)na okre(cid:258)li(cid:202) krótki opis wyja(cid:258)niaj(cid:200)cy przeznaczenie danego fragmentu kodu. Przeanalizujmy przyk(cid:239)ad przedstawiony na rysunku 6.11. 211 Poleć książkęKup książkę J(cid:266)zyk C# w 7 dni. Solidne podstawy programowania obiektowego Rysunek 6.11. Regiony kodu (cid:283)ród(cid:239)owego tworzone przy u(cid:285)yciu dyrektyw #region oraz #endregion Okno edytora widoczne z lewej strony rysunku 6.11 przedstawia rozwini(cid:218)ty region utworzony przy u(cid:285)yciu dyrektyw #region … #endregion, pokazuj(cid:200)cy, jak mo(cid:285)na je stosowa(cid:202). Z kolei okno edytora zamieszczone z prawej strony pokazuje, jak wygl(cid:200)da zwini(cid:218)ty region. Po umieszczeniu wska(cid:283)nika myszy na tek(cid:258)cie opisu regionu poni(cid:285)ej zostanie wy(cid:258)wietlony prostok(cid:200)tny obszar prezentuj(cid:200)cy jego zawarto(cid:258)(cid:202). A zatem wcale nie trzeba rozwija(cid:202) regionu, by przejrze(cid:202) umieszczony w nim kod (cid:283)ród(cid:239)owy. Dyrektywa #line Dyrektywa #line pozwala zmieni(cid:202) numer wiersza, który b(cid:218)dzie wy(cid:258)wietlany w komunikatach kompilatora. Dodatkowo mo(cid:285)na w niej tak(cid:285)e okre(cid:258)li(cid:202) nazw(cid:218) pliku, która b(cid:218)dzie wy(cid:258)wietlana w tych komunikatach, cho(cid:202) ta mo(cid:285)liwo(cid:258)(cid:202) jest opcjonalna. Ta dyrektywa mo(cid:285)e by(cid:202) przydatna w zautomatyzowanych etapach procesu budowania kodu. W przypadkach, gdy z pierwotnego kodu (cid:283)ród(cid:239)owego zosta(cid:239)y usuni(cid:218)te numery wierszy, wyniki b(cid:218)d(cid:200) musia(cid:239)y by(cid:202) generowane na pod- stawie numeracji wierszy pierwotnego pliku (cid:283)ród(cid:239)owego. Z kolei dyrektywa o postaci #line default przywraca normalny sposób numerowania wierszy kodu. Zastosowanie dyrektywy o postaci #line hidden sprawia, (cid:285)e ani nazwa pliku, ani numeracja wierszy kodu w komunikatach generowanych przez kompilator nie b(cid:218)dzie modyfikowana. I w ko(cid:241)cu dyrektywa o postaci #line nazwa_pliku daje mo(cid:285)liwo(cid:258)(cid:202) okre(cid:258)lenia nazwy pliku, która ma by(cid:202) wy(cid:258)wietlana w komunikatach generowanych przez kompilator. Nazwa pliku musi by(cid:202) zapisana w cudzys(cid:239)owach i umieszczona przed ewentualnym numerem wiersza. Przeanalizujmy poni(cid:285)szy fragment kodu: public void LinePreprocessor() { #line 85 LineprocessorIsTheFileName WriteLine( Ta instrukcja jest w wierszu nr 85, a nie nr 25. ); 212 Poleć książkęKup książkę Dzie(cid:276) 6. — Dok(cid:225)adniejszy przegl(cid:261)d zagadnie(cid:276) zaawansowanych #line default
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Język C# w 7 dni. Solidne podstawy programowania obiektowego
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


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