Zadania (21-30)
Zadanie 21
Section titled “Zadanie 21”Rola operatorów is oraz as w języku C#
Section titled “Rola operatorów is oraz as w języku C#”Operator is sprawdza, czy obiekt jest danego typu (lub typu pochodnego), i zwraca wartość logiczną true/false. Od C# 7 łączy się go z dopasowaniem wzorca, dzięki czemu w jednym kroku można sprawdzić typ i przypisać obiekt do nowej zmiennej.
Operator as próbuje rzutować obiekt na wskazany typ referencyjny lub typ dopuszczający null. Jeśli rzutowanie się nie powiedzie, zwraca null zamiast rzucać wyjątek (w przeciwieństwie do zwykłego rzutowania w nawiasach, które zgłasza InvalidCastException). Dlatego as jest bezpieczniejszy, gdy nie mamy pewności co do typu.
object o = "tekst";
// is sprawdza typ i zwraca bool; tu od razu z przypisaniem do zmiennej sif (o is string s){ Console.WriteLine(s.Length);}
// as próbuje rzutować; przy niepowodzeniu zwraca null (bez wyjątku)string t = o as string;if (t != null){ Console.WriteLine(t);}Skrót do zapamiętania: is sprawdza typ i zwraca bool (z możliwym dopasowaniem wzorca). as próbuje rzutować i przy niepowodzeniu zwraca null zamiast wyjątku.
- is: test typu -> bool; od C# 7 z pattern matching (
o is string s). - as: bezpieczne rzutowanie typów referencyjnych/nullable; niepowodzenie -> null.
- Zwykłe rzutowanie
(Typ)oprzy błędzie rzuca InvalidCastException. - as używamy, gdy nie mamy pewności co do typu.
Zadanie 22
Section titled “Zadanie 22”Konstrukcja match (wzorce aktywne) i funkcje rekurencyjne w F#
Section titled “Konstrukcja match (wzorce aktywne) i funkcje rekurencyjne w F#”Konstrukcja match … with w F# to rozbudowane dopasowanie wzorców, działające jak wielokrotny switch, ale potrafiące dodatkowo rozbijać strukturę danych i wiązać jej części ze zmiennymi. Każdy przypadek to wzorzec poprzedzony kreską pionową, a _ oznacza dowolną wartość.
Wzorce aktywne (active patterns) pozwalają definiować własne kategorie dopasowania w nawiasach z kreskami pionowymi, np. podział liczb na parzyste i nieparzyste. Funkcje rekurencyjne deklaruje się słowem let rec i często łączy z match, gdzie jeden przypadek jest warunkiem zakończenia (bazowym), a drugi zawiera wywołanie rekurencyjne.
// funkcja rekurencyjna - oznaczona slowem reclet rec factorial n = // dopasowanie wzorca do wartosci n match n with // przypadek bazowy konczacy rekurencje | 0 -> 1 // przypadek ogolny z wywolaniem rekurencyjnym | _ -> n * factorial (n - 1)
// aktywny wzorzec dzielacy liczby na Even i Oddlet (|Even|Odd|) n = if n % 2 = 0 then Even else Odd
// uzycie aktywnego wzorca w matchlet describe n = match n with | Even -> "parzysta" | Odd -> "nieparzysta"Skrót do zapamiętania: match…with to dopasowanie wzorców (switch z rozbijaniem struktury). Wzorce aktywne (|A|B|) to własne kategorie dopasowania. Funkcje rekurencyjne to let rec, zwykle z przypadkiem bazowym w match.
- match…with: dopasowanie wzorca,
|na przypadek,_= dowolny. - Potrafi rozbijać strukturę i wiązać części ze zmiennymi.
- Wzorce aktywne: własne wzorce definiowane jako
(|A|B|). - Rekurencja:
let rec, przypadek bazowy + wywołanie rekurencyjne.
Zadanie 23
Section titled “Zadanie 23”Program w F# do obchodzenia drzewa binarnego (post-order oraz dwa pozostałe porządki)
Section titled “Program w F# do obchodzenia drzewa binarnego (post-order oraz dwa pozostałe porządki)”Drzewo binarne reprezentujemy jako typ unii: węzeł z wartością i dwoma poddrzewami albo liść (pusty). Obchodzenie realizujemy funkcjami rekurencyjnymi, które różnią się jedynie kolejnością łączenia wyników. W post-order odwiedzamy najpierw lewe poddrzewo, potem prawe, na końcu korzeń. W in-order: lewe, korzeń, prawe. W pre-order: korzeń, lewe, prawe. Operator @ łączy listy.
// definicja drzewa binarnego: lisc (pusty) lub wezel z wartoscia i dwoma poddrzewamitype Tree = | Leaf | Node of int * Tree * Tree
// post-order: lewe, prawe, korzenlet rec postOrder tree = match tree with // pusty lisc daje pusta liste | Leaf -> [] // najpierw lewe poddrzewo, potem prawe, na koncu wartosc wezla | Node(v, l, r) -> postOrder l @ postOrder r @ [v]
// in-order: lewe, korzen, prawelet rec inOrder tree = match tree with | Leaf -> [] // lewe poddrzewo, wartosc, prawe poddrzewo | Node(v, l, r) -> inOrder l @ [v] @ inOrder r
// pre-order: korzen, lewe, prawelet rec preOrder tree = match tree with | Leaf -> [] // najpierw wartosc, potem lewe i prawe poddrzewo | Node(v, l, r) -> [v] @ preOrder l @ preOrder r
// przykladowe drzewolet tree = Node(1, Node(2, Leaf, Leaf), Node(3, Leaf, Leaf))
// wypisanie wynikow obchodzeniaprintfn "post-order: %A" (postOrder tree)printfn "in-order: %A" (inOrder tree)printfn "pre-order: %A" (preOrder tree)Skrót do zapamiętania: Drzewo to typ unii (Leaf | Node of wartosc, lewe, prawe). Trzy rekurencyjne funkcje różnią się tylko kolejnością: post = L,P,korzeń; in = L,korzeń,P; pre = korzeń,L,P. Listy łączy @.
- Typ:
Leaf | Node of int * Tree * Tree. - post-order:
postOrder l @ postOrder r @ [v]. - in-order:
inOrder l @ [v] @ inOrder r. - pre-order:
[v] @ preOrder l @ preOrder r. - Wszystkie rekurencyjne (let rec) z dopasowaniem match.
Zadanie 24
Section titled “Zadanie 24”Przeciążanie operatorów w F#
Section titled “Przeciążanie operatorów w F#”W F# operatory można przeciążać, definiując je jako statyczne składowe typu (klasy lub rekordu) o nazwie operatora w nawiasach, np. (+). Działa to analogicznie do C#: gdy użyjemy operatora na obiektach danego typu, wywoła się nasza definicja. Można też definiować własne operatory infiksowe na poziomie modułu.
// typ Vector z przecionym operatorem +type Vector(x: int, y: int) = // wlasnosci tylko do odczytu member this.X = x member this.Y = y // przeciazenie operatora + jako statyczna skladowa typu static member (+) (a: Vector, b: Vector) = // tworzymy nowy wektor jako sume skladowych Vector(a.X + b.X, a.Y + b.Y)
// uzycie operatora na obiektach Vectorlet v = Vector(1, 2) + Vector(3, 4)Skrót do zapamiętania: W F# operator przeciąża się jako statyczną składową typu o nazwie operatora w nawiasach, np. static member (+) (a, b) = .... Można też tworzyć własne operatory infiksowe.
- Składnia:
static member (+) (a, b) = ...wewnątrz typu. - Działa po użyciu operatora na obiektach tego typu.
- Można definiować własne operatory infiksowe (na poziomie modułu).
- Idea jak w C#, inna składnia.
Zadanie 25
Section titled “Zadanie 25”Modele programowania ADO.NET - dwa modele dostępu do baz danych
Section titled “Modele programowania ADO.NET - dwa modele dostępu do baz danych”ADO.NET udostępnia dwa podstawowe modele dostępu do danych: połączeniowy i bezpołączeniowy. Różnią się one tym, czy połączenie z bazą jest utrzymywane przez cały czas pracy na danych.
Model połączeniowy opiera się na obiekcie DataReader. Połączenie z bazą jest otwarte przez cały czas odczytu, a dane czyta się strumieniowo, tylko do przodu i tylko do odczytu. Jest szybki i oszczędny pamięciowo, ale blokuje połączenie i nie pozwala swobodnie nawigować po danych.
Model bezpołączeniowy opiera się na obiektach DataSet i DataAdapter. Dane pobiera się do pamięci (DataSet to lokalna kopia danych), po czym połączenie jest zamykane. Można na nich pracować w trybie offline, a zmiany zsynchronizować z bazą później przez DataAdapter. Zużywa więcej pamięci, ale jest elastyczny i nie trzyma otwartego połączenia.
Skrót do zapamiętania: Połączeniowy (DataReader): połączenie cały czas otwarte, odczyt do przodu, szybki, mało pamięci. Bezpołączeniowy (DataSet/DataAdapter): dane w pamięci, połączenie zamykane, praca offline, więcej pamięci.
- Połączeniowy: DataReader, otwarte połączenie, odczyt strumieniowy do przodu, szybki.
- Bezpołączeniowy: DataSet + DataAdapter, dane w pamięci, połączenie zamykane.
- Połączeniowy oszczędza pamięć, bezpołączeniowy daje elastyczność i pracę offline.
- Łącznikiem z bazą jest Connection; polecenia wykonuje Command.
Zadanie 26
Section titled “Zadanie 26”Opisać klasę Page stosowaną na poziomie aplikacji ASP.NET
Section titled “Opisać klasę Page stosowaną na poziomie aplikacji ASP.NET”Klasa Page (System.Web.UI.Page) w ASP.NET Web Forms reprezentuje pojedynczą stronę .aspx. Każda strona aplikacji jest w istocie klasą dziedziczącą z Page, generowaną na podstawie pliku .aspx i powiązanego kodu (code-behind). Obiekt tej klasy jest tworzony przy każdym żądaniu strony.
Klasa Page zarządza cyklem życia strony i udostępnia kluczowe właściwości oraz zdarzenia. Najważniejsze właściwości to IsPostBack (czy strona jest wynikiem ponownego wysłania formularza), Request, Response, Session, ViewState i kontrolki strony. Najważniejsze zdarzenia cyklu życia to Init, Load, zdarzenia kontrolek oraz PreRender i Unload.
Skrót do zapamiętania: Page (System.Web.UI.Page) reprezentuje stronę .aspx; każda strona to klasa dziedzicząca z Page. Zarządza cyklem życia strony i udostępnia IsPostBack, Request, Response, Session oraz zdarzenia Init/Load/PreRender/Unload.
- Reprezentuje stronę .aspx; każda strona dziedziczy z System.Web.UI.Page.
- Tworzona przy każdym żądaniu, zarządza cyklem życia strony.
- Właściwości: IsPostBack, Request, Response, Session, ViewState, kontrolki.
- Zdarzenia: Init, Load, PreRender, Unload.
Zadanie 27
Section titled “Zadanie 27”Podać i omówić rodzaje transakcji
Section titled “Podać i omówić rodzaje transakcji”Transakcja to zbiór operacji wykonywanych jako jedna, niepodzielna całość, spełniający zasady ACID (atomowość, spójność, izolacja, trwałość). Albo wszystkie operacje się powiodą i zmiany zostaną zatwierdzone (commit), albo żadna i nastąpi wycofanie (rollback).
Pod względem zasięgu wyróżnia się transakcje lokalne i rozproszone. Transakcja lokalna obejmuje jeden zasób (jedną bazę danych) i jest zarządzana przez jeden menedżer transakcji. Transakcja rozproszona obejmuje wiele zasobów lub baz, koordynowanych przez wspólny menedżer (np. MSDTC), zwykle z protokołem zatwierdzania dwufazowego (two-phase commit). W .NET transakcje wygodnie obsługuje TransactionScope, który sam decyduje, czy potrzebna jest transakcja lokalna czy rozproszona.
Skrót do zapamiętania: Transakcja to niepodzielny zbiór operacji (ACID): commit albo rollback. Rodzaje wg zasięgu: lokalne (jeden zasób/baza, jeden menedżer) i rozproszone (wiele zasobów, koordynacja MSDTC, two-phase commit).
- Transakcja = niepodzielny zbiór operacji, zasady ACID.
- Commit (zatwierdzenie) albo rollback (wycofanie).
- Lokalna: jeden zasób/baza, jeden menedżer transakcji.
- Rozproszona: wiele zasobów, koordynator (MSDTC), zatwierdzanie dwufazowe.
- W .NET: TransactionScope.
Zadanie 28
Section titled “Zadanie 28”Wyjaśnić pojęcie plików XML i podać przykład takiego pliku
Section titled “Wyjaśnić pojęcie plików XML i podać przykład takiego pliku”XML (Extensible Markup Language) to tekstowy, rozszerzalny format opisu danych w strukturze hierarchicznej (drzewiastej). Dane przechowuje się w znacznikach, które programista definiuje samodzielnie, dzięki czemu format jest samoopisujący i czytelny zarówno dla człowieka, jak i dla maszyny. XML służy głównie do przechowywania oraz wymiany danych między różnymi systemami niezależnie od platformy.
Plik XML ma jeden element nadrzędny (korzeń), wewnątrz którego zagnieżdżone są kolejne elementy. Elementy mogą mieć atrybuty i wartości tekstowe.
<?xml version="1.0" encoding="UTF-8"?><!-- element korzenia --><book> <!-- elementy zagniezdzone z wartosciami --> <title>Pan Tadeusz</title> <author>Adam Mickiewicz</author> <year>1834</year></book>Skrót do zapamiętania: XML to tekstowy, hierarchiczny, samoopisujący format danych z definiowanymi przez użytkownika znacznikami; służy do przechowywania i wymiany danych między systemami. Ma jeden korzeń i zagnieżdżone elementy.
- XML = tekstowy, rozszerzalny, hierarchiczny format danych.
- Znaczniki definiuje użytkownik -> samoopisujący.
- Jeden element korzenia, w nim zagnieżdżone elementy (z atrybutami i wartościami).
- Zastosowanie: przechowywanie i wymiana danych niezależnie od platformy.
Zadanie 29
Section titled “Zadanie 29”Czym jest serializacja obiektów w języku C#?
Section titled “Czym jest serializacja obiektów w języku C#?”Serializacja to proces zamiany obiektu (jego stanu, czyli wartości pól) na postać nadającą się do zapisu lub przesłania, np. strumień bajtów, tekst XML albo JSON. Deserializacja to proces odwrotny: odtworzenie obiektu z takiej zapisanej postaci. Dzięki temu obiekty można zapisać do pliku, przesłać siecią lub przechować w pamięci podręcznej, a później je odtworzyć.
W C# do serializacji służą m.in. XmlSerializer (do XML), JsonSerializer (do JSON) oraz dawniej serializacja binarna. Klasy przeznaczone do serializacji oznaczano atrybutem [Serializable], a poszczególne pola można dostosowywać atrybutami.
using System.Text.Json;
// klasa, której obiekty chcemy serializowaćclass Person{ public string Name { get; set; } public int Age { get; set; }}
// utworzenie obiektuPerson p = new Person { Name = "Ala", Age = 20 };
// serializacja obiektu do tekstu JSONstring json = JsonSerializer.Serialize(p);
// deserializacja - odtworzenie obiektu z tekstu JSONPerson restored = JsonSerializer.Deserialize<Person>(json);Skrót do zapamiętania: Serializacja to zamiana obiektu na zapisywalną/przesyłalną postać (bajty, XML, JSON), deserializacja to proces odwrotny. W C#: XmlSerializer, JsonSerializer, atrybut [Serializable].
- Serializacja: obiekt -> bajty/XML/JSON (do zapisu lub przesłania).
- Deserializacja: postać zapisana -> obiekt.
- Narzędzia: XmlSerializer, JsonSerializer (binarna - dawniej).
- Zastosowanie: zapis do pliku, przesył siecią, cache.
Zadanie 30
Section titled “Zadanie 30”Przedstawić sposób obsługi błędów jakie mogą pojawić się w aplikacjach ASP.NET
Section titled “Przedstawić sposób obsługi błędów jakie mogą pojawić się w aplikacjach ASP.NET”W aplikacjach ASP.NET błędy obsługuje się na kilku poziomach. Najniższy to lokalna obsługa w kodzie blokami try-catch-finally, gdy spodziewamy się konkretnego błędu i chcemy go obsłużyć od razu. Wyższy poziom to obsługa na poziomie strony przez zdarzenie Page_Error, a najwyższy to obsługa globalna na poziomie całej aplikacji przez zdarzenie Application_Error w pliku Global.asax.
Dodatkowo w pliku konfiguracyjnym web.config sekcja customErrors pozwala zdefiniować przyjazne strony błędów wyświetlane użytkownikowi zamiast technicznych komunikatów (np. osobna strona dla błędu 404). Metoda Server.GetLastError() pozwala pobrać ostatni wyjątek, a Server.ClearError() go wyczyścić. W ASP.NET Core obsługę błędów realizuje się przez middleware (np. UseExceptionHandler).
Skrót do zapamiętania: Trzy poziomy: lokalnie try-catch, na poziomie strony Page_Error, globalnie Application_Error (Global.asax). Plus przyjazne strony błędów w web.config (customErrors) i Server.GetLastError().
- Lokalnie: try-catch-finally w kodzie.
- Na poziomie strony: zdarzenie Page_Error.
- Globalnie: Application_Error w Global.asax.
- web.config -> customErrors: przyjazne strony błędów (np. 404).
- Server.GetLastError() pobiera ostatni wyjątek; w ASP.NET Core - middleware.