Autor: Michał Dobrzycki
Microsoft wypuścił dwa narzędzia, Visual Studio oraz Visual Studio Code. To są dwa różne narzędzia.
Potrzebujemy trzech aplikacji do wykonania ćwiczeń z C#:
Gdzie szukać informacji o Visual Studio (IDE)
Definiuje sposób tworzenia, hostowania i obsługi pakietów dla platformy .NET
Dostarcza też narzędzia do zarządzania nimi
nuget.exe to manager paczek (coś jak npm dla JS albo maven dla Javy)
Paczka nugetowa, to nic innego jak plik ZIP, który ma w środku skompilowane binarki projektu napisanego w C#.
Kilka linków:
Platforma udostępniona przez Microsoft dla developerów, do tworzenia wielu rodzajów aplikacji, takich jak:
Aplikacje .NET można tworzyć dla wielu systemów operacyjnych, na przykład:
Aktualna najnowsza wersja .NET to 6.0
My będziemy korzystać na tym kursie z wersji 3.1 (LTS)
Czym dla nas jest .NET (praktycznie)
Język C# jest:
C#
public class Program() {
public static void Main(string[] args) {
Console.Writeline("Hello world!");
}
}
JavaScript
console.log("Hello world!");
Cecha | C# | JavaScript |
---|---|---|
Obiektowy | TAK | TAK |
Funkcyjny | TAK | TAK |
Kompilowany | TAK | NIE |
Wielowątkowy | TAK | NIE |
Działa w przeglądarce | NIE | TAK |
Wsparcie BDD | TAK | TAK |
Praca z ORM/DB | ŁATWA | TRUDNA |
Próg wejścia | ŚREDNI | NISKI |
Jakby odpowiedział konsultant
To zależy...
Wszystkie zadania z C# będziemy wykonywać w jednym projekcie
Zróbcie forka i klona na swoje maszyny z tego repozytorium, żeby móc wypychać swoje zmiany na githuba.
Jak definiujemy zmienne w C#?
Musimy podać im typ oraz nazwę zmiennej, przypisać wartość i zakończyć średnikiem
public class Movies()
{
int movieNumber = 65;
string merchandise = "Avengers";
}
Magiczne słówko var, powoduje że C# sam się domyśli jaki to ma być typ.
Zapis poniżej jest równoznaczny z poprzednim
public class Movies()
{
var movieNumber = 65;
var merchandise = "Avengers";
}
Rozwiążcie zadania 1-3 z modułu:
01-WstepStringi w C# są niezmienialnymi (immutable) obiektami
Możemy je deklarować na kilka sposobów:
public class Example() {
string text1; // bez inicjalizacji
string text2 = null; // inicjalizacja nullem
string text3 = System.String.Empty; // pusty string jest równoznaczny z string text3 = ""
string escapePath = "c:\\Users\\Programista";
var noEscapePath = @"c:\Users\Programista";
}
Interpolacja ciągów (string interpolation)
Możemy wstawiać zmienne do środka stringów:
public static void Main(string[] args)
{
string name = "Michał";
string surname = "Dobrzycki";
double stanKredytu = -300000.43;
string doDruku = $"Witaj {name} {surname}, twoje aktualne zadłużenie konta wynosi {stanKredytu}";
}
Na Stringach można pracować jak z tablicami znaków
public static void Main(string[] args)
{
string s = "Kobyla ma maly bok";
char[] charArray = s.ToCharArray();
// możemy używać wbudowanych funkcji tablic https://docs.microsoft.com/pl-pl/dotnet/api/system.array?view=netcore-3.1
string reversed = new string( charArray );
}
Rozwiążcie zadania 4-6 z modułu:
01-WstepInstrukcje warunkowe
Instrukcja if:
public static void Main(string[] args)
{
if (warunek1) {
// jeżeli warunek1 jest TRUE to wykonaj kod
} else if (warunek2) {
// jeżeli warunek1 jest FALSE oraz warunek2 jest TRUE to wykonaj kod
} else {
// jeżeli wszystkie warunki powyżej są FALSE to wykonaje ten kod
}
}
Instrukcje warunkowe
Tenary operator
public static void Main(string[] args)
{
var zmienna = (warunek) ? a : b;
// if (warunek)
// {
// zmienna = a;
// }
// else
// {
// zmienna = b;
// };
}
Instrukcje warunkowe
Instrukcja switch (zamiennie do if):
public static void Main(string[] args)
{
// załóżmy że użytkownik podaje zmienną typu int age z klawiatury
switch (age) {
case < 0:
Console.WriteLine("Nie można mieć mniej niż 0 lat");
break;
case > 150:
Console.WriteLine("Nie można mieć mniej więcej niż 150 lat");
break;
case 42:
Console.WriteLine("Douglas Adams bardzo lubi ten wiek!");
break;
default:
Console.WriteLine($"Masz {age} lat!");
break;
}
Rozwiążcie zadania 7-9 z modułu:
01-WstepW C# punktem wejściowym do programu jest funkcja public static void Main()
Metody to funkcje (bloki kodu zawierające instrukcje), które przyjmują dane na wejściu i zwracają przetworzone dane (być może innego typu) na wyjściu
Metody muszą coś zwracać, a jeżeli nie zwracają używamy słowa void (zwracamy pustkę)
W C# każda instrukcja jest wykonywana w kontekście metody.
Metody definiujemy za pomocą schematu
[atrybut dostępu] [static] typ_zwracany NazwaMetody(int parametr1, ...)
Elementy w nawiasach kwadratowych są opcjonalne, opowiemy o nich później.
Przykłady definicji metod
public static double CalculateGross(int netto, double vat) { return netto + (netto * vat) };
string GetFullName(string name, string surname) { return $"{name} {surname}"};
void SendSMS(string email, string message) { /* kod wysyłający email */ };
Rozwiążcie zadania 1-3 z modułu:
01-WstepOd .NET 3.1 w górę możemy używać bardziej skomplikowanego dopasowania wzorców
Musimy zrobić tutaj trick ze znakiem _, którego używamy jako placeholder dla zmiennej
int result = x switch
{
_ when x > 0 && y > 0 => zwróć taką wartość,
_ when x > 0 && y < 0 => zwróć taką wartość,
_ when x < 0 && y < 0 => zwróć taką wartość,
_ when x < 0 && y > 0 => zwróć taką wartość,
_ => 0
};
Rozwiążcie zadania 10-14 z modułu:
01-WstepDebugowanie to krokowe i kontrolowane wykonywanie programu. Visual Studio pozwala nam wykonać program linijka po linijce.
Rozwiążcie zadania modułu:
02-DebugowanieCzym są wyjątki?
Wyjątek są po to, żebyśmy mogli radzić sobie z niespodziewanymi sytuacjami w kodzie.
Wyobraźcie sobie co może się stać jeżeli:
Jak obsługujemy wyjątki?
try
{
result = 10/0;
Console.WriteLine(result);
}
catch (DivideByZeroException e)
{
Console.WriteLine("Attempted divide by zero.");
}
Jak rzucać wyjątkiem z naszych funkcji?
Możemy tworzyć własne wyjątki lub rzucać gotowymi. Np. Selenium tworzy kilkanaście specyficznych dla siebie wyjątków.
throw new Exception("Treść wyjątku");
Czas na zadania z działu 03-Wyjątki
Podstawowymi strukturami danych potrzebnymi w testach automatycznych są:
Tablice
Dodajemy [] na końcu typu zmiennej żeby zdefiniować tablicę. Musimy również podać jej długość. Raz zdefiniowanej długości nie możemy już zmienić.
int[] myIntArray = new int[5] { 1, 2, 3, 4, 5 };
Enum - typ wyliczeniowy
Tworzymy go poza klasą po to, żeby ograniczyć liczbę możliwych wartości
public enum Season
{
Spring,
Summer,
Autumn,
Winter
}
Listy
Struktury przypominające tablice, ale tablice na sterydach (możemy zmieniać jej długość). Przechowują kolekcję konkretnych typów.
{
List<int> numberList = new List<int>();
numberList.Add(54);
numberList.Add(45);
numberList.Remove(45); // remove an item
numberList.RemoveAt(0); // remove item with index 0
}
Szybkie definiowanie list z danymi
List<string> names = new List<string>()
{
"Jan",
"Bogna",
"Zofia"
}
Słowniki
Struktura danych trzymająca pary danych klucz - wartość.
Dictionary<string, string> openWith = new Dictionary<string, string>();
openWith.Add("txt", "notepad.exe");
openWith.Add("bmp", "paint.exe");
Czytanie danych ze słowników, używamy try-catch
try
{
Console.WriteLine("For key = \"tif\", value = {0}.", openWith["tif"]);
}
catch (KeyNotFoundException)
{
Console.WriteLine("Key = \"tif\" is not found.");
}
Lepsze czytanie danych ze słownika. Uwaga: magiczne słówko out
string value = "";
if (openWith.TryGetValue("tif", out value))
{
Console.WriteLine("For key = \"tif\", value = {0}.", value);
}
else
{
Console.WriteLine("Key = \"tif\" is not found.");
}
Czas na zadania z działu 04-Struktury-danych
Cztery filary programowania obiektowego:
Klasy, czyli przepis na tworzenie obiektu
Myślimy o rzeczywistości w postaci obiektów (rzeczowników). Obiekty te mają swoje:
public class Car
{
public double horsePower; // właściwość
public static void Main(string[] args) { ... } // metoda
}
Konstruktor, czyli ustawianie danych przy tworzeniu obiektu
Jeżeli utworzymy klasę to wszystkie właściwości będą miały domyślne wartości.
Możemy zmienić to zachowanie konstruktorem który wymusza ustawienie wartości pól podczas tworzenia obiektu.
public class Car
{
public double horsePower; // właściwość
public Car(double horsePower)
{
this.horsePower = horsePower;
}
}
Interfejsy, czyli definicja zachowania dla klas
interface IWebDriver<T>
{
void Quit(); // każdy webdriver musi potrafić zamknąć przeglądarkę
IWebElement FindElement(); // i znaleźć element na stronie
}
Czas na zadania z działu 05-Obiekty
Properties
Czas na zadania z działu 05-Modyfikatory
Pomocne linki dla regexów:
Czytanie plików do stringa
Dokumentacja klasy File
Ważne: żeby móc korzystać w trybie build z pliku tekstowego, musimy po jego dodaniu kliknąć na Properties i ustawić "Copy to output directory" na wartość "Copy always". Domyślnie ustawione jest "Do not copy".
string wynnik = File.ReadAllText("plik.txt");
Przypomnienie wzorców:
Jak używamy ich w C#
public static void Main(string[] args)
{
// używajmy głównie @"" żeby traktować znak \ jako część regexa
string wyszukiwany = "...";
Regex re = new Regex(@"wzorzec");
// znajdź wszystkie wystąpienia (możemy po nich iterować)
MatchCollection result = re.Matches(wyszukiwany);
foreach (Match r in result)
{
Console.WriteLine(r.Value);
}
}
Co zrobić żeby traktować każdą linijkę stringa/pliku jako osobny string
public static void Main(string[] args)
{
// znajdź od początku linii wielkie litery
Regex re = new Regex(@"^[A-Z]+", RegexOptions.Multiline);
}
Czas na zadania z działu 07-RegEx
Służy trzem celom:
Lambdy możemy wrzucać do środka jako funkcje anonimowe
string[] words = { "bot", "apple", "apricot" };
int minimalLength = words
.Where(w => w.StartsWith("a"))
.Min(w => w.Length);
Expression body definition jest popularne dla krótkich funkcji.
Na przykład nadpisanie metody toString obiektu.
public override string ToString() => $"{fname} {lname}".Trim();
Czas na zadania z działu 08-ArrowFunctions
Język zapytań charakterystyczny dla C#. Przypomina trochę SQL. Służby do szukania elementów w kolekcjach, plikach XML i bazach danych.
Wybór i obróbka elementów
var powers = numbers.Select(x => x * x);
lub statycznie definiując
IEnumerable powers = numbers.Select(x => x * x);
var dobrePiwa = beers.Where(p => p.Contains("pełne"));
Jeżeli potrzebujemy Listę, to możemy użyć:
var greaterThan50 = numbers.Where(e => e>50).ToList();
Zakładając że mamy Listę obiektów:
new Customer(){ Name="Bartosz Walaszek", OrdersQuantity=40, TotalPurchasesAmount=8345.66, Bank="MIL"},
Możemy grupować elementy tej listy po wybranych polach (properties)
var banks = customers.GroupBy(b => b.Bank);
To zwraca nam coś "jakby" słownik gdzie kluczem będzie nazwa banku.
Możemy posortować obiekty według konkretnych pól
var banks = customers.OrderBy(b => b.OrdersQuantity);
Pobierz pierwszy lub wartość domyślną (w przeciwieństwie do First() jest bardziej bezpieczne)
List<int> months = new List<int> { };
int firstMonth = months.FirstOrDefault(); // zwraca 0 mimo pustej tablicy
Inne funkcje agregujące (do znalezienia w dokumentacji):
Czas na zadania z działu 09-Linq