obiektowka Flashcards
virtual vs abstract
metody
metoda:
-virtual:
+daje możliwość odwołania się do metody bazowej
+może mieć implementację w klasie pochodnej
+może mieć ciało
-abstract:
+nie daje możliwości odwołania się do metody bazowej
+musi mieć implementacji w klasie pochodnej
+nie może mieć ciała
+tylko w klasie abstrakcyjnej
Klasa abstrakcyjna
Klasa abstrakcyjna nie może mieć swoich reprezentantów
pod postacią obiektów.
Klasa abstrakcyjna jest wykorzystywana wyłącznie w roli
klasy bazowej dla innych klas.
Klasa staje się abstrakcyjną, gdy zawiera choćby jedną
abstrakcyjną metodę lub właściwość.
Klasa potomna względem klasy abstrakcyjnej musi
implementować wszystkie jej abstrakcyjne metody
i właściwości.
Klasa abstrakcyjna może zawierać także pola
oraz nieabstrakcyjne metody i właściwości.
Klasa zamknięta (finalna)
Klasa zamknięta nie może być bazową
dla klas od niej pochodnych.
Klasy zamknięte zapobiegają
przypadkowemu dziedziczeniu.
Metody zamknięte (finalne) stosuje się wówczas,
gdy działanie metody jest sprawdzone, poprawne, stabilne
i nie wymaga dalszych zmian.
Interfejs
-Interfejs jest tworem abstrakcyjnym podobnym do klasy,
ale posiada on jedynie deklaracje składowych,
które od C#8 może dodatkowo implementować.
-Nie można utworzyć obiektu będącego instancją interfejsu.
-Interfejs może zawierać: zagnieżdżone typy (np. klasy),
stałe, metody, właściwości, zdarzenia, indeksery.
-Interfejs nie może zawierać pól, operatorów,
konstruktorów i destruktorów.
-Klasa może dziedziczyć tylko po jednej klasie, ale może
implementować wiele interfejsów lub dziedziczyć po nich.
-Klasa implementująca interfejs może być tak samo lub
bardziej dostępna niż interfejs.
-Interfejs rozszerzający nie może być bardziej dostępny od
któregokolwiek interfejsu bazowego.
-Interfejs może być interfejsem rozszerzającym dla wielu
innych interfejsów (gdy po nich dziedziczy).
-Interfejsy mogą być włączone w dowolne miejsce hierarchii
dziedziczenia, w przeciwieństwie do klas abstrakcyjnych.
interfejs vs klasa abstrakcyjna
abstrakcja:
-nie może mieć obiektów
-wszystkie abstrakcyjne muszą być implementowane
-określone miejsce w hierarchii
-jedna klasa abstrakcyjna
-może mieć: pola, operatory, konstruktory, destruktory
interfejs:
-też nie może mieć obiektów
-wszystkie bez funkcjonalności muszą być implementowane
-dowolne miejsce w hierarchii
-wiele interfejsów
-nie może mieć: pól, operatorów, konstruktorów, destruktorów
SOLID
S — zasada pojedynczej odpowiedzialności
(SRP, ang. Single Responsibility Principle)
O — zasada otwarte-zamknięte
(OCP, ang. Open-Closed Principle)
L — zasada podstawienia Liskov
(LSP, ang. Liskov Substitution Principle)
I — zasada separacji interfejsów
(ISP, ang. Interface Segregation Principle)
D — zasada odwrócenia zależności
(DIP, ang. Dependency Inversion Principle)
Zasada pojedynczej odpowiedzialności
(SRP, ang. Single Responsibility Principle) mówi,
że każda klasa (a zatem obiekt) powinna odpowiadać
za jak najmniejszy fragment logiki programu.
Stosowanie zasady SRP redukuje odpowiedzialność
każdej z klas i zwiększa prawdopodobieństwo
ponownego ich użycia.
Zasada otwarte-zamknięte (OCP, ang. Open-Closed
Principle) mówi, że klasy, moduły, funkcje itp. powinny być
otwarte na rozszerzenia, a zamknięte na modyfikacje.
Zgodnie z zasadą OCP powinna istnieć możliwość
uzyskania nowych funkcjonalności
poprzez rozszerzenie elementu
(np. przez dziedziczenie
lub tworzenie statycznych metod rozszerzających),
a nie zmianę już istniejącego.
Zasada podstawienia Liskov mówi, że: „funkcje, które
używają wskaźników lub referencji do klas bazowych,
muszą być w stanie używać również obiektów klas
dziedziczących po klasach bazowych, bez dokładnej
znajomości tych obiektów”…
…co w praktyce oznacza przede wszystkim to, że
klasa dziedzicząca po klasie bazowej nie powinna zmieniać
jej funkcjonalności, tylko rozszerzać możliwości.
Zasada separacji interfejsów (ISP, ang. Interface
Segregation Principle) mówi, że tworzone interfejsy muszą
być odpowiedzialne za jak najmniejszą funkcjonalność.
Wynika to z faktu, że nadmienienie rozbudowany interfejs
(zwany tłustym lub zanieczyszczonym) wymaga
implementacji w klasach potomnych metod,
które być może nie będą nigdy wykorzystane.
Zasada odwrócenia zależności (DIP, ang. Dependency
Inversion Principle) mówi, że kod warstw wyższego poziomu
(np. klas potomnych) nie powinien zależeć od kodu niższych
warstw (np. klas bazowych).
Zgodnie z DIP obie warstwy powinny być od siebie
niezależne, ale zależeć od pewnych abstrakcji.
Jednocześnie abstrakcje nie powinny zależeć od
szczegółów.
Kolejność wykonywania konstruktorów
1) statyczne i klas bazowych w kolejności dziedziczenia
2) konstruktory obiektowych pól klasy
3) konstruktory klasy
Metoda statyczna
Z czym związana?
jest zatem związana z typem
(nie instancją, czyli obiektem).
Klasa statyczna
Kiedy się stosuje?
Różnice między niestatyczną
Dziedziczenie
Klasy statyczne stosuje się, gdy nie ma potrzeby korzystania
z indywidualnego stanu klasy.
Klasa statyczna może zawierać metody i pola statyczne.
Klasa niestatyczna może zawierać metody i pola statyczne
oraz niestatyczne
Klasa statyczna nie może implementować interfejsów
i brać udziału w dziedziczeniu.
Do klas statycznych nie odnosi się this, base (dziedziczenie).
Konstruktor statyczny
kiedy używany?
jest używany wówczas, gdy należy
zainicjalizować statyczną składową niestatycznej klasy bez
konieczności tworzenia instancji klasy.
Konstruktor statyczny uruchamiany jest w chwili tworzenia
pierwszego obiektu niestatycznej klasy tylko 1. raz, po nim
uruchamiane są (wielokrotnie) konstruktory niestatyczne.
Operator konwersji niejawnej (np. double poleFigury = prostokąt1; )
Operator konwersji jawnej (np. double poleFigury = (double)prostokąt1; )
Operator jednoargumentowy (np. Liczba liczbaOdwrotna=-liczba; )
Operator dwuargumentowy (np. Liczba liczba=liczba1+liczba2; )
public static implicit operator typwyjściowy(typwejściowy arg1)
public static explicit operator typwyjściowy(typwejściowy arg1)
public static typwyniku operator typoperatora1arg(typargu1 arg1)
public static typwyniku operator typoperatora2arg(typargu1 arg1 ,typargu2 arg2)
Przeciążając operatory == i !=, należy również
i co robią?
nadpisać
metody Equals() i GetHashCode(), które są dziedziczone po
klasie System.Object. W przeciwnym przypadku kompilator
zgłosi ostrzeżenie.
TRZEBA JE PRZECIĄŻĄĆ PARAMI
Metoda Equals() działa jak operator == i sprawdza,
czy porównywane obiekty są równe.
dla typów referencyjnych porównuje referencje
Metoda GetHashCode()
zwraca swego rodzaju
identyfikator obiektu. Jest
on zawsze równy dla tych
samych reprezentacji
w pamięci, ale nie musi
być różny dla różnych
obiektów (powtarza się co
ok. 10 tyś. obiektów)
GUID
co to? rozmiar? jak użyć?
Zmienne GUID (globally unique identifier) są 128b (16B)
liczbami całkowitymi, które mogą być używane tam, gdzie
wymagane są niepowtarzalne identyfikatory (m.in.
w b.d., w których klucz główny musi być unikatowy, np. w
przypadku, gdy ocena może być dodana do dowolnego
zasobu aplikacji, więc jej identyfikator musi być unikatowy).
Guid Guid1 = Guid.NewGuid();
aby przeciążyć operatory true false
należy również przeciążyć operatory które zwracają te wartości
Indeksator jest
Indeksatory pozwalają
Indeksator musi zawierać
Indeksatory mogą być przekazywane jako argumenty metod
Dlaczego nie może być statyczny?
kolekcją podobną do tablicy
ale indeksy mogą być innych typów
niestatyczny
Nie można tworzyć statycznych indeksatorów,
ponieważ indeksatory są powiązane z obiektami.
wygodnie odwoływać się do tablicy
lub innej struktury danych zadeklarowanej w klasie.
co najmniej jedną deklarację
dostępu get lub set (podobnie jak właściwość).
Składnia indeksatora jest analogiczna do właściwości.
[modyfikatory] typ this[argumenty_indeksów]{
deklaracje_dostępu //skojarzenie wartości z indeksami
}
tylko przez wartość. Nie mogą być więc one przekazywane
przez referencję (ref) i wyjście (out).
Struktury
jaki typ?
kiedy stosować?
dziedziczenie czy mogą, co z interfejsem
przypisywanie wartości i struktur
co mogą zawierać?
modyfikator readonly
jak działa new?
Struktury są mniej rozbudowaną alternatywą dla klas.
Struktury są typem wartości (bezpośrednim), nie zaś typem
referencyjnym, zatem niejawnie dziedziczą po klasie
bazowej „System.ValueType” (choć ta dziedziczy po Object).
Struktury należy wykorzystywać dla prostych, niewielkich
(do 16 bajtów) i krótkotrwałych danych, które są tworzone na
stosie. Gwarantuje to wówczas wydajność większą
niż w przypadku stosowania obiektów klas.
Struktury nie obsługują dziedziczenia,
ale mogą implementować interfejsy.
Podczas przypisania zmiennych typu struktura wartości
są kopiowane - powstają dwie odrębne kopie
tych samych danych.
Struktury są podobne do klas: mogą zawierać stałe, pola,
metody, właściwości, indeksatory, zdarzenia, konstruktory,
przeciążone operatory.
Struktury nie mogą zawierać bezpośredniej inicjalizacji pól
typu: int i=10;.
W strukturze od C#10 można definiować konstruktor
bezparametrowy (tak jak każdy), ale musi inicjować wszystkie parametry
struktury. Nie można natomiast tworzyć finalizerów.
Modyfikator readonly stosuje się do tych składowych struktur
(np. metod), które nie modyfikują ich stanu.
Słowo new nie oznacza działań typowych dla klas i
obiektów: nie tworzy nowego obiektu na stercie, ale oznacza
wywołanie konstruktora bezparametrowego w celu
inicjalizacji wszystkich pól struktury
(kompletnego stanu struktury)
klasa vs struktura
Klasa to typ referencyjny zorientowany na przechowywanie
wartości bardziej złożonych i ukierunkowany na
odwzorowywanie pewnej hierarchii przy użyciu hermetyzacji,
dziedziczenia i mechanizmów używanych w konstrukcji
dynamicznych struktur danych.
Struktura to typ wartościowy zorientowany na
przechowywanie wartości, która jest nieco bardziej
rozbudowana od typów pierwotnych (int, double, etc.)
i nie zajmuje więcej niż 16 bajtów na stosie
Dwie zmienne typu klasa (obiekty) są traktowane jako równe
gdy są tego samego typu i odwołują się dokładnie do tego
samego obiektu – obszaru na stercie (sposób działania
porównania można zmienić).
Dwie zmienne typu struktura, rekord i rekord struktury są
traktowane jako równe gdy są tego samego typu, a wartości
ich pól są sobie równe.
rekord (klasy) vs rekord struktury
Rekord (record class) to typ referencyjny zorientowany na
przechowywanie wartości bardziej złożonych, ale raczej
niezmiennych - przeznaczonych głównie do odczytu.
Takimi danymi są np. dane statystyczne. W deklaracji można
pisać record lub record class.
Rekord struktury to typ wartościowy – niereferencyjny.
W deklaracji pisze się record struct. Rekord struktury,
w przeciwieństwie do rekordu, jest przeznaczony do
przechowywania danych, które mogą się zmieniać.
Tablice
Tablice to zbiory wielu zmiennych tego samego typu.
Tablice umożliwiają przeprowadzanie operacji
na grupach obiektów.
Typ elementów tablicy wskazywany jest
z chwilą jej deklaracji.
Przydział pamięci na stercie dla określonej liczby elementów
następuje w momencie tworzenia tablicy. Są typami
referencyjnymi.
Istnieją tablice jednowymiarowe, wielowymiarowe
oraz tablice o różnej liczbie elementów w wierszach
lub kolumnach.
W tablicach oprócz typów wbudowanych można
przechowywać również klasy i struktury itd.
Każda tablica dziedziczy po abstrakcyjnej klasie
System.Array, która dostarcza podstawowych mechanizmów
do działania na elementach tablicy.
Do deklaracji tablicy służy operator [].
Tablice są indeksowane od wartości „0” do „n-1”, gdzie n to
liczba elementów tablicy
Do tworzenia bardziej złożonych i wyspecjalizowanych
struktur danych oraz efektywnego zarządzania nimi służą
kolekcje (inny wykład).
int[,] t4 ; //deklaracja bez alokacji
int[,] t5= new int[3,2]; //alokacja
dwu wymiarowe tablice ^
int[][] <- tez dwuwymiarowa
Predykaty wyszukiwawcze
co to?
jak deklarować?
Wyszukiwanie w tablicach bazuje na predykatach
wyszukiwawczych - metodach definiujących kryteria wysz.
Predykaty wyszukiwawcze można deklarować w wygodny
sposób z wykorzystaniem wyrażeń lambda.
Wyrażenia lambda
co to?
co zawiera?
jak można przekazywać argumenty?
Wyrażenia lambda to maksymalnie
uproszczone metody anonimowe.
Wyrażenia lambda zawierają jedynie
listę parametrów i ciało metody.
Wyrażenia lambda nie mają nazwy
oraz nie definiują typu zwracanego.
Gdy wyrażenie lambda przyjmuje jeden argument,
nie trzeba otaczać go nawiasami ().
Gdy ciało funkcji zawiera tylko jedną instrukcję, nie trzeba
używać klamerek {} ani słowa kluczowego return.
Zmienne zdefiniowane w ciele wyrażenia lambda
są usuwane po zakończeniu działania metody.
Można przekazywać do wyrażeń lambda parametry
poprzez referencję i wyjście.
Nie trzeba podawać typów parametrów dla zmiennych
przekazanych przez wartość, natomiast wymagane jest
podanie typu parametru dla zmiennych przekazanych
przez referencję i wyjście.
Zwracane wartości muszą pasować do kontekstu użycia
(typu danego delegata).
Func<>
co to?
co posiada?
Jakie parametry?
przeciazanie
Typy parametrow
Func<> jest delegatem generycznym, zatem jest osadzony
na wskazanych typach parametrów wejściowych
i wyjściowych.
Ma zero lub więcej parametrów wejściowych i dokładnie
jeden parametr wyjściowy. Jest to parametr ostatni.
Func<> można definiować bezpośrednio w kodzie.
Func<> wymaga podania typu parametrów oraz typu
zwracanego wyniku (ostatni parametr).
Func<> dysponuje konstruktorem przeciążonym 17 razy, tj.
Func<out>, Func<in, out>, Func<in1, in2, out>, Func<in1,
in2, in3, out> itd.</out>
nie da się przeciążać funkcji zadeklarowanej za pomocą func
Action<>
co to?
co posiada?
Action<> jest delegatem generycznym, który bazuje
wyłącznie na parametrach wejściowych (musi posiadać co
najmniej 1)- nie posiada on parametrów wyjściowych.
Action<> w pozostałych kwestiach jest zbliżony do Func<>.
Testy jednostkowe (ang. unit test)
Testy jednostkowe (ang. unit test) to metoda testowania
tworzonego oprogramowania polegająca na przygotowaniu
i wykonaniu dedykowanych testów.
Test jednostkowy wywiąże się z wykonaniem testowanego
fragmentu kodu i porównaniem wyniku z ustalonym przez
autora testu wynikiem wzorcowym (np. czy metoda Dodaj()
dla argumentów 2 i 2 powinna zwrócić 4).
Test jednostkowy to (inaczej) kod wykonujący inny kod
w warunkach kontrolowanych, który służy do weryfikacji
poprawności tego drugiego.
Testy jednostkowe pozwalają automatyzować proces
tworzenia oprogramowania, są zatem podstawą wielu
podejść do tworzenia oprogramowania (np. ekstremalnego).
Autor testu dostarcza dane wejściowe oraz informację
o oczekiwanym rezultacie, celem testu jest porównanie
rezultatu oczekiwanego z rezultatem otrzymanym.
NuGet
NuGet jest systemem zarządzania pakietami w postaci
rozszerzenia do Visual Studio, ułatwiającym zarządzanie
referencjami do bibliotek.
Realizuje kłopotliwe i czasochłonne operacje: (0)wyszukania
po nazwie odpowiedniej biblioteki, (1)ściągnięcia jej,
(2)rozpakowania, (3)dodania referencji oraz (4)aktualizacji
pliku konfiguracyjnego. Realizuje też operację usuwania.
Biblioteki konfiguruje się niezależnie
w kontekście poszczególnych aplikacji.
Testy jednostkowe
Dobre praktyki
T.j. należy pisać dla każdej metody, która reprezentuje jakąś
funkcjonalność.
T.j. powinny pokrywać całą funkcjonalność metody.
T.j. powinny być niezależne od siebie i od środowiska, w
którym są wykonywane. Należy unikać sytuacji, w których
wynik jednego testu zależy od wyniku innego testu.
T.j. powinny być szybkie i działać w izolacji.
T.j. nie powinny korzystać z sieci, bazy danych lub innych
zewnętrznych źródeł danych.
T.j. powinny być łatwe do zrozumienia i utrzymania. Należy
dbać o czytelność kodu testów i komentarze.
T.j. powinny być uruchamiane automatycznie za pomocą
dedykowanych narzędzi.
T.j. nie eliminują wszelkich problemów w kodzie, ale są
jednym z narzędzi, które pomaga w poprawie jego jakości.
T.j. powinny być pisane równolegle z kodem produkcyjnym.
Nie należy zostawiać ich pisania na koniec, ponieważ może
to prowadzić do wykrycia problemów na późnym etapie, co
może skutkować koniecznością przebudowy już napisanego
kodu.
T.j. należy uruchamiać regularnie i śledzić ich wyniki. W
przypadku pojawienia się błędów, należy jak najszybciej je
naprawić.
T.j. powinny być pisane z myślą o ich czytelności i możliwości
ponownego użycia. Mogą być one cennym źródłem
informacji dla programistów, którzy będą pracować z danym
kodem w przyszłości.
T.j. powinno umieszczać się w tym samym rozwiązaniu,
co właściwa aplikacja, ale w oddzielnym projekcie (szablon:
projekt testowy NUnit) <-był komentarz. W przykładzie klasa
testująca została dla uproszczenia dodana do wspólnego
projektu (tj. biblioteka klas, interfejs1, interfejs2, etc.).
Klasa Mock
Klasa Mock (mock to imitacja) z biblioteki Moq lub
NSubstitute umożliwia tworzenie obiektów zastępczych, które
pozwalają na ścisłe kontrolowanie zachowania innych
obiektów podczas testów
Użycie klasy Mock jest ważne, ponieważ rzeczywiste obiekty
mogą być skomplikowane w implementacji: ich zachowanie
nie jest pewne, ich tworzenie jest pracochłonne, ich
tworzenie może prowadzić do problemów związanych z
zależnościami między klasami. Użycie Mock ułatwia zatem
testowanie i eliminuje niepożądane skutki uboczne tworzenia
obiektów rzeczywistych.
Klasy Fake są często używane do testowania całych
systemów, klasy Stub są przydatne w testowaniu
jednostkowym, klasy Spy pozwalają wywoływać rzeczywiste
metody dla oryginalnego obiektu i jego atrapy.
Innymi klasami pozwalającymi tworzyć obiekt zastępcze są
np.: klasa Fake z biblioteki FakeItEasy, klasa Stub z biblioteki
Rhino.Mocks, klasa Spy z biblioteki Mockito.NET, etc..
Obiekty zastępcze eliminują konieczność użycia zasobów
zewnętrznych (baz danych, strumieni, etc.). Przykładowo
mogą one symulować działanie bazy danych
i zwracać odpowiednie dane testowe.
Test-driven development (TDD)
Na bazie testów powstała technika tworzenia
oprogramowania Test-driven development (TDD).
TDD polega na wielokrotnym powtarzaniu sekwencji kroków:
Krok 1/3. Napisanie testu sprawdzającego dodawaną
funkcjonalność, który wykazuje błąd,
bo funkcjonalność początkowo nie istnieje.
Krok 2/3. Implementacja funkcjonalności,
która powinna przejść pomyślenie test.
Krok 3/3. Refaktoryzacja kodu,
by spełniał określone standardy.
string
jaki typ? Jak traktowany?
modyfikacja
Jak wywoływane metody?
Każda operacja na ciągu wymusza tworzenie nowego
obiektu typu string. Zatem kod np. string s=”a”; s=”b”;
tworzy po sobie dwie nowe instancje s w pamięci.
Zatem zmiennych string nie powinno się często
modyfikować, gdyż obniża to wydajność (przy licznych
modyfikacjach należy stosować StringBuilder- cd. wykładu).
Klasa string jest typem referencyjnym (dziedziczy po
System.Object), ale jej obiekty deklaruje się
jak zmienne typów prostych
(w typowych zastosowaniach nie używa się new). W C++
obiekty klasy std::string są typami wartościowymi.
W przeciwieństwie do pozostałych typów referencyjnych typ
„string” jest w języku C# traktowany jak typ prosty (choć jest
referencyjny), a zatem może być deklarowany jako stała
i może mieć przypisywane stałe wartości typu string.
Zmiennej string przypisuje się wartość stałą na dwa
sposoby: jako stałe dosłowne @”tekst”
oraz stałe standardowe ”tekst”.
Wyjątkiem przy
ciągach dosłownych
jest znak “”, który jest
zamieniany na “.
Metody klasy string można wywoływać na dwa sposoby:
z poziomu instancji (obiektu) lub jako statyczne.
Interpolowany ciąg znaków jest oznaczany
znakiem specjalnym
Interpolowany ciąg znaków jest oznaczany
znakiem specjalnym $.
Można łączyć z @
Interpolowany ciąg znaków może zawierać wyrażenia,
które są finalnie zmieniane w ciąg znaków.
(wstawianie do stringu czegoś)
string a = null
vs
string a = string.Empty
Przypisanie null oznacza, że nie znamy wartości.
Przypisanie Empty oznacza, że znamy wartość,
ale nie dotyczy ona inicjalizowanej zmiennej.
string.Copy() vs string.Clone()
Copy() kopiuje zmienną w pamięci,
Clone() tworzy tylko kopię referencji.
string porównywanie
Porównanie przez Equals lub operator „==” – podejścia nie
pozwalające zdefiniować dodatkowych opcji: np.
ignorowania wielkości liter, ustawień regionalnych etc.
Porównanie CompareTo – niestatyczna metoda
porównująca zmienne string bez możliwości definiowania
dodatkowych opcji.
Porównanie Compare – statyczna metoda
porównująca zmienne string
z możliwością definiowania dodatkowych opcji
Porównanie CompareOrdinal – statyczna metoda
porównująca zmienne string na podstawie ich kodów ASCII
(kodów liczbowych) bez możliwości definiowania
dodatkowych opcji (zwraca np. wartość 32 w przypadku
porównania litery a i A).
StringBuilder
po co?
co reprezentuje?
jak zamienić na string?
Każda zmiana zmiennej string wiąże się z przepisaniem
ciągu znaków do nowego obszaru na stercie.
Jest to największa wada obiektów typu string.
Gdy przewiduje się częstą modyfikację ciągów znaków
zaleca się stosowanie klasy System.Text.StringBuilder.
Obiekt klasy StringBuilder reprezentuje tablicę znaków
o zmiennej długości: rezerwuje w pamięci pewien obszar
roboczy, na którym można wykonywać operacje.
Konstruktor klasy StringBuilder pozwala wskazać:
- początkowy rozmiar tablicy znaków (capacity),
- dopuszczalny rozmiar tablicy znaków (maxCapacity)
lub/i - ciąg znaków inicjalizujący tablicę znaków (value).
Wywołanie metody ToString() dla obiektu klasy StringBuilder
powoduje przekonwertowanie tablicy znaków
do zmiennej string.
StringBuilder
Zestawienie ważniejszych metod
Append()
AppendFormat()
AppendLine()
Insert()
Remove()
Replace()
ToString()
Clear()
Append() dodaje tekst na końcu obszaru obiektu
StringBulider
AppendFormat()
dodaje tekst wraz z formatowaniem
(analogicznym jak dla Console.Write())
na końcu obszaru obiektu StringBulider
AppendLine() wstawia znak końca linii
Insert() wstawia ciąg znaków
we wskazanym miejscu
Remove() usuwa wskazaną część ciągu znaków
Replace() zamienia wskazaną część łańcucha
znaków
ToString() konwertuje tablicę znaków do string
Clear() usuwa aktualną zawartość obiektu
Regex
Wyrażenia regularne (ang. REGular EXpressions) stosuje
się tam, gdzie nie ma możliwości użycia klas string i charnp. przy sprawdzeniu, czy nazwa pliku pasuje do wzorca.
Wyrażenia regularne można wyeliminować, ale zastępczy
kod jest: długi, nieczytelny, podatny na błędy i nieelastyczny.
Wyrażenia regularne pozwalają efektywnie zarządzać
fragmentami ciągów znaków, które są dopasowane
do wskazanego wzorca.
Wyrażenia regularne mogą być także wykorzystywane
w walidacji wprowadzanych danych
Klasa Regex określa wyrażenia regularne
do reprezentowania wzorców ciągów znaków.
Klasa Regex definiuje metody do przeszukiwania,
wydobywania i zastępowania tekstu.
Metody klasy Regex można wywoływać z poziomu instancji
lub jako statyczne.
Regex scenariusze użycia
IsMatch
Match
NextMatch
Matches
Replace
Split
Escape
Unescape
Walidacja dopasowania (IsMatch) pozwala sprawdzić,
czy wzorzec jest obecny.
Pobranie pierwszego (jednego) dopasowania (Match),
potem kolejnych (Match.NextMatch).
Pobranie wszystkich dopasowań
(Matches, zwraca MatchCollection).
Zastąpienie dopasowań (Replace).
Dekompozycja dopasowań (Split) na tablicę.
Zastąpienie znaków {\, *, +,?, |, {, [, (,), ^, $, ., # oraz białych}
przez ich odpowiedniki traktowane dosłownie (Escape).
Przykładowo znak ‘ * ’ jest zastępowany przez ‘ \ \ * ’, dzięki
czemu przestaje być np. przez obiekty Regex traktowany
jako „0 lub wiele wystąpień”.
Realizacja odwrotna do przedstawionej wyżej (Unescape).
Lazarus
Lazarus (http://www.lazarus-ide.org) to zintegrowane
środowisko programistyczne oparte na kompilatorze Free
Pascal i wzorowane na Delphi.
Lazarus bazuje na założeniu, aby raz napisana aplikacja
kompilowała się wszędzie (write once compile anywhere),
czyli na różne platformy. Jest to podejście odmienne od
tego, aby raz napisana aplikacja działała wszędzie (write
once run anywhere).
GRASP
Zasady GRASP są uzupełnieniem zasad SOLID.
Zasady GRASP (ang. General Responsibility Assignment
Software Patterns, ogólne wzorce ustalania
odpowiedzialności w oprogramowaniu) określają
odpowiedzialność klas i obiektów w systemie.
Każda zasada GRASP wyjaśnia inny problem
dotyczący ustalania odpowiedzialności.