- Lekcja 2. Środowisko programowania C# Tworzymy pierwszy program
- Lekcja 3. Zmienne. Typy zmiennych
- Lekcja 4. Operatory w C#
- Lekcja 5. Instrukcje warunkowe (decyzje w programie)
- Lekcja 6. Pętle (Powtarzanie zadań)
- Lekcja 7. Funkcje i Metody (Budowanie własnych narzędzi)
- Lekcja 8. Tablice i Kolekcje (Przechowywanie wielu danych)
- Lekcja 9. Praca z Plikami (Odczyt i Zapis danych, w tym JSON)
Lekcja 1. Czym jest język C#? Typowanie i kompilacja vs interpretacja
C# to nowoczesny, obiektowy język programowania opracowany przez firmę Microsoft w 2000 roku. Jego twórcą jest Anders Hejlsberg, znany też z pracy nad językiem Delphi. C# został zaprojektowany do tworzenia różnorodnych aplikacji – od konsolowych, przez aplikacje desktopowe, webowe, mobilne, aż po gry komputerowe (np. w silniku Unity).
Założenia C#:
- Czytelność: kod powinien być przejrzysty i zrozumiały nawet po czasie,
- Obiektowość: wszystko opiera się na klasach i obiektach,
Co to jest programowanie obiektowe?
Wyobraź sobie, że program to świat złożony z różnych rzeczy, które coś robią i mają jakieś cechy. Na przykład:
Samochód – ma kolor, markę i potrafi jechać
Uczeń – ma imię, wiek i potrafi się uczyć
Telefon – ma model, producenta i potrafi dzwonić
Każda z tych rzeczy to obiekt.
Co to jest klasa?
Klasa to przepis, jak stworzyć daną rzecz. Tak jak:
przepis na pizzę mówi, co trzeba przygotować i jak to złożyć,
klasa Samochod mówi, że samochód ma kolor, markę i może jechać.
Co to jest obiekt?
Obiekt to konkretna rzecz stworzona według przepisu (klasy). - Bezpieczeństwo: język chroni programistę przed błędami typów i operacji nielegalnych,
- Modularność: aplikacje można budować z wielu współpracujących elementów,
- Wieloplatformowość: dzięki .NET i .NET MAUI można pisać aplikacje działające na Windows, Androidzie, Macu itd.,
- Kompilacja: kod C# jest kompilowany do kodu pośredniego (IL), który uruchamiany jest przez środowisko .NET (CLR).
Typowanie i kompilacja vs interpretacja
Czym jest typowanie? Typowanie to zasada przypisywania określonego typu danym, np. czy dana zmienna to liczba, tekst, wartość logiczna itp. Typowanie określa, co można zrobić z daną zmienną i jakie operacje są dozwolone.
Statyczne typowanie (C#):
- Typ zmiennej jest określany na etapie pisania programu,
- Program nie skompiluje się, jeśli wystąpi niezgodność typów,
- Przykład:
int liczba = "tekst";– błąd kompilacji.
Dynamiczne typowanie (Python):
- Typ zmiennej określany jest dopiero w trakcie działania programu,
- Więcej swobody, ale większe ryzyko błędów w czasie uruchomienia,
- Przykład:
liczba = "tekst"– działa, dopiero później może dać błąd.
Statyczne typowanie: przyspiesza wykrywanie błędów już na etapie kompilacji, co z kolei prowadzi do mniej błędów w czasie wykonywania.
Dynamiczne typowanie: mimo że daje większą elastyczność, może prowadzić do trudności w utrzymaniu kodu w większych projektach.
Kompilacja (C#):
- Kod źródłowy jest najpierw przekształcany w kod pośredni (IL), a potem wykonywany przez maszynę wirtualną (CLR),
- Błędy wykrywane już na etapie kompilacji,
- Szybsze działanie programu po uruchomieniu.
Interpretacja (Python):
- Kod wykonywany jest linijka po linijce bez wcześniejszego kompilowania,
- Błędy widoczne dopiero w czasie uruchamiania programu,
- Dobrze do szybkiego prototypowania, ale wolniejsze wykonywanie.
C# vs Python – podobieństwa i różnice:
| Cecha | C# | Python |
|---|---|---|
| Typowanie | Statyczne | Dynamiczne |
| Składnia | Bardziej formalna, wymaga deklaracji | Luźna, bardziej zbliżona do języka naturalnego |
| Wydajność | Wyższa (kompilowany) | Niższa (interpretowany) |
| Zastosowania | Aplikacje Windows, Unity, MAUI | Skrypty, data science, web, automatyzacja |
| Obsługa projektów | Wymaga tworzenia struktury projektu | Można pisać pojedyncze pliki |
Uwaga dla .NET 8/9 (top-level statements)
W nowych projektach C# metoda Main() może być niewidoczna, bo kompilator generuje ją „w tle”. Taki jednolinijkowy program:
Console.WriteLine("Witaj w C#!");
jest kompletnym programem. To normalne w .NET 6+ (w tym .NET 8/9).
Lekcja 2. Środowisko programowania C# Tworzymy pierwszy program
Możemy pisać programy w C# w dwóch popularnych środowiskach:
1. Visual Studio Code (VS Code):
- Lekkie, darmowe środowisko
- Wymaga instalacji SDK .NET i rozszerzenia C#
- Projekty tworzy się przez terminal:
mkdir KalkulatorSrednich
cd KalkulatorSrednich
dotnet new console
Aby uruchomić program wpisujemy w konsoli
dotnet run
2. Visual Studio 2022:
- Rozbudowane środowisko z graficznym interfejsem
- Wybieramy: Nowy projekt > Aplikacja konsolowa (.NET)
- Nie trzeba używać terminala
Struktura projektu C# (zarówno w VS Code, jak i VS 2022):
| Folder/plik | Co robi? | Co uczeń powinien wiedzieć? |
|---|---|---|
| Program.cs | Twój kod | Tu piszesz program |
| .csproj | „plan projektu” | Mówi .NET, co i jak ma być kompilowane |
| bin/ | „fabryka wyników” | Tu trafia gotowy .exe |
| obj/ | „śmieci techniczne” | Nie ruszamy – używa to kompilator |
Global using
W projektach .NET 8/9 wiele using jest dodawanych globalnie (np. w GlobalUsings.cs). Kod zadziała nawet, gdy nie widać using System;.
KalkulatorSrednich/
├── Program.cs ← główny plik z kodem
├── KalkulatorSrednich.csproj ← plik konfiguracyjny projektu
├── bin/ ← pliki wynikowe (.exe, .dll) – działa tylko po kompilacji
│ └── Debug/
│ └── net8.0/
│ └── KalkulatorSrednich.exe
├── obj/ ← pliki robocze kompilatora (.cache, .pdb)
Pierwszy program
Teoria: Program w C# zawsze zaczyna się od klasy z metodą Main(), która jest punktem wejścia.
Ale UWAGA! Nowe szablony w .NET 8/9
Szablon „Aplikacja konsolowa” tworzy program z ukrytym Main() (top-level statements). Dlatego możesz nie widzieć klasy Program. To nie błąd.
Kod „Hello World”:
using System; // dodanie przestrzeni nazw
class Program
{
static void Main()
{
Console.WriteLine("Witaj, świecie!"); // wypisanie tekstu
}
}
Wyjaśnienie linijek:
using System;– pozwala korzystać z podstawowych klas jak Console (załaduj „bibliotekę” do wypisywania na ekran (Console.WriteLine) – innymi słowy – to instrukcja, która „importuje” lub „włącza” przestrzeń nazwSystem, która zawiera wiele podstawowych klas, takich jakConsole. To trochę jak otwieranie książki kucharskiej, w której znajdują się przepisy na dania (funkcje).class Program– definicja klasy, wszystko w C# musi być w klasie (tworzymy klasę o nazwie Program – kontener na kod)static void Main()– Główna metoda – to właśnie ona się uruchamia na startConsole.WriteLine(...)– wypisuje tekst do konsoli
Wejście – wyjście danych:
Console.Write("Podaj swoje imię: ");
string imie = Console.ReadLine();
Console.WriteLine($"Cześć, {imie}!");
Console.Write(„Podaj swoje imię: „); – To wyświetlenie komunikatu na ekranie bez przechodzenia do nowej linii. – Konsola wypisze Podaj swoje imię: i czeka dalej w tej samej linii.
string imie = Console.ReadLine(); – To pobranie danych wpisanych przez użytkownika z klawiatury (np. “Grzesiek”). – Wszystko co wpisze użytkownik i zatwierdzi Enterem, trafia do zmiennej imie jako tekst (string).
Console.ReadLine() zawsze zwraca tekst, więc jeśli chcesz liczbę, musisz go potem przekonwertować np. int.Parse().
- Console.WriteLine(…) – wypisuje tekst i przechodzi do nowej linii.
- $”Cześć, {imie}!” – to łańcuch interpolowany, czyli taki, w którym możesz bezpośrednio wkładać zmienne w tekst, np. {imie} zostanie zamienione na „Grzesiek”.
- Efekt: program wypisze np. Cześć, Grzesiek!
Podsumowując
| Czynność | Kod | Co robi? |
|---|---|---|
| Wyświetlenie tekstu | Console.Write() | Pisze coś na ekranie (bez nowej linii) |
| Pobranie danych | Console.ReadLine() | Czeka, aż użytkownik coś wpisze |
| Zapis do zmiennej | string zmienna = … | Przechowuje to, co wpisał użytkownik |
| Wyświetlenie z wynikiem | Console.WriteLine(…) | Pisze coś + przechodzi do nowej linii |
PODSUMOWANIE:
Z czego składa się program w C#? (czyli krótka tabela do zapamiętania)
| Element | Co to jest? | Przykład | Opis uczniowski |
|---|---|---|---|
| using | dyrektywa | using System; | Włącza gotową bibliotekę funkcji, np. Console.WriteLine |
| class | klasa | class Program | „Pudełko” na kod – każda funkcja musi być w klasie |
| Main() | metoda | static void Main() | Start programu – pierwsze, co się uruchamia |
| Console.WriteLine() | funkcja | Console.WriteLine(„Hello”) | Wyświetla coś w konsoli i przechodzi do nowej linii |
| Console.ReadLine() | funkcja | string imie = Console.ReadLine(); | Pobiera dane wpisane z klawiatury |
| string, int, bool | typ danych | int wiek = 17; | Określa rodzaj danych: tekst, liczba, prawda/fałsz |
Porównanie C# vs Python – mały test logiczny
| Scenariusz | C# | Python | Uwaga |
|---|---|---|---|
| Przypisanie tekstu do liczby | ❌ Błąd kompilacji (int x = „tekst”;) | ✅ Przejdzie (x = „tekst”) | Python sprawdzi dopiero w trakcie działania |
| Brak Main() | ❌ Program nie działa | ✅ Kod działa od góry do dołu | C# zawsze potrzebuje Main() |
| Brak średnika ; | ❌ Błąd kompilacji | ✅ Python nie używa średników | W C# każdy rozkaz kończysz ; |
| Można pisać pojedynczy plik? | ❌ Lepiej mieć strukturę projektu | ✅ Wystarczy 1 plik | C# wymaga .csproj, plików klas itd. |
Zadanie na podsumowanie.
Napisz program, który:
- Prosi użytkownika o imię
- Wita użytkownika imieniem
- Pyta o wiek
- Wypisuje komunikat: „Twoje imię, masz 17 lat. Za rok będziesz mieć 18!”
A oto przykład rozwiązania. Przeanalizuj poniższy kod i wykonaj dialog pomiędzy programem, a użytkownikiem.
using System;
class Program
{
static void Main()
{
Console.Write("Podaj swoje imię: ");
Console.ReadLine(); // Uczeń jeszcze nie wie, że można to zapisać do zmiennej
Console.WriteLine("Cześć!");
Console.Write("Ile masz lat? ");
Console.ReadLine();
Console.WriteLine("Twoje imię, masz 17 lat. Za rok będziesz mieć 18!");
}
}
Jak to się ma do desktopu i MAUI
- Konsola: start w
Program.cs. - WinForms/WPF: logika startu w
App.xaml/Form1.cs. - .NET MAUI: konfiguracja w
MauiProgram.cs, a aplikacja wApp.xaml.cs.
Składnia C# i logika są te same – zmienia się tylko sposób interakcji (konsola vs kontrolki UI).
Lekcja 3. Zmienne. Typy zmiennych
Co to jest zmienna?
Zmienna to kontener na dane. Można ją sobie wyobrazić jako pojemnik z etykietą, który trzyma jakąś wartość.
Wyobraź sobie pudełko opisane jako „wiek”. W środku zapisujesz liczbę 17. To właśnie jest zmienna: ma nazwę (np. wiek) i przechowuje wartość (np. 17).
💡 W programie zmienna to zaadresowana część pamięci komputera, gdzie przechowywana jest informacja. Komputer musi wiedzieć:
* jak nazywa się ta zmienna* jakiego typu są dane (czy to tekst? liczba? prawda/fałsz?)
* jaka jest aktualna wartość
Typy danych – czyli co może zawierać zmienna
C# wymaga, by każda zmienna miała określony typ – to trochę jak etykieta na pudełku: „tu są tylko liczby całkowite” albo „tu może być tylko tekst”.
Rodzaje zmiennych w C# (Typy danych).
1. Typy proste (typy wartościowe – Value Types)
| Typ | Opis | Przykład |
|---|---|---|
| int | Liczba całkowita (4 bajty) | int liczba = 42; |
| long | Długa liczba całkowita (8 bajtów) | long duza = 1234567890; |
| short | Krótsza liczba całkowita (2 bajty) | short male = 32000; |
| byte | Liczba od 0 do 255 (1 bajt) | byte bajt = 255; |
| sbyte | Liczba -128 do 127 (1 bajt) | sbyte liczba = -100; |
| float | Liczba zmiennoprzecinkowa (4 bajty) | float f = 3.14f; |
| double | Dokładniejsza liczba (8 bajtów) | double d = 3.141592; |
| decimal | Dokładne liczby (np. do pieniędzy) | decimal cena = 99.99m; |
| bool | Wartość logiczna (true/false) | bool prawda = true; |
| char | Jeden znak (literka) | char znak = 'A’; |
2. Typy tekstowe (Reference Types)
| Typ | Opis | Przykład |
|---|---|---|
| string | Tekst (ciąg znaków) | string imie = „Ania”; |
| object | Może przechować cokolwiek | object cos = 5; |
object to najbardziej ogólny typ – każda zmienna w C# pochodzi od object.
3. Typy złożone – mniej spotykane na początku nauki
| Typ | Opis | Przykład |
|---|---|---|
| DateTime | Data i godzina | DateTime teraz = DateTime.Now; |
| TimeSpan | Różnica czasu | TimeSpan t = TimeSpan.FromHours(2); |
| Guid | Unikalny identyfikator | Guid id = Guid.NewGuid(); |
| var | Automatyczne wykrycie typu | var x = 5; (tu x to int) |
Deklarowanie zmiennych – jak to się pisze?
// tekst
string imie = "Ania";
// liczba całkowita
int wiek = 18;
// liczba z przecinkiem
double temperatura = 36.6;
// prawda/fałsz
bool czyPada = true;
// jeden znak
char litera = 'B';
Konwersja typów – zamiana jednej zmiennej na inny typ
Czasem trzeba zamienić tekst na liczbę, albo liczbę na tekst. Oto jak to robimy:
Tekst →Liczba (string→ int, double)
string wpis = "25";
int liczba = int.Parse(wpis);
string wpis2 = "3.14";
double liczb_Z_Przecinkiem = double.Parse(wpis2);
Uwaga: int.Parse() zadziała tylko, jeśli wpisany tekst to poprawna liczba. W przeciwnym razie program się wywali.
Liczba → Tekst (int, double → string)
int liczba = 42;
string tekst = liczba.ToString();
double d = 3.14;
string napis = d.ToString();
Praktycznie w UI: TryParse
W aplikacjach okienkowych i mobilnych dane z pól tekstowych bywają błędne. Zamiast int.Parse(...) używaj:
if (int.TryParse(tekst, out int liczba)) { /* OK */ } else { /* komunikat o błędzie */ }
Unikasz wyjątków i masz czytelny warunek.
Przykładowy program – użycie różnych typów zmiennych
using System;
class Program
{
static void Main()
{
string imie = "Grzesiek";
int wiek = 17;
double temperatura = 36.6;
bool czyZdrowy = true;
char ocena = 'A';
Console.WriteLine("Imię: " + imie);
Console.WriteLine("Wiek: " + wiek);
Console.WriteLine("Temperatura: " + temperatura + " °C");
Console.WriteLine("Zdrowy? " + czyZdrowy);
Console.WriteLine("Ocena z informatyki: " + ocena);
}
}
Zadanie 1 – Zamień tekst na liczbę
Program pyta użytkownika o jego wiek, wpisany jako tekst, a potem zamienia go na liczbę i wypisuje:
Masz 18 lat, czyli za 2 lata będziesz mieć 20.
Zadanie 2 – Liczba na tekst
Zapisz liczbę 42 do zmiennej int, a potem wypisz ją jako tekst w zdaniu:
„Twoja szczęśliwa liczba to 42” – ale liczba musi być częścią string, nie int.
Zadanie 3 – Prawda czy fałsz
Napisz program, który ma zmienną bool czyUczen = true;
Jeśli czyUczen jest true, wypisz: „Witaj uczniu!”, jeśli false – „To program tylko dla uczniów!”
Lekcja 4. Operatory w C#
W poprzedniej lekcji nauczyliśmy się, czym są zmienne i typy danych – czyli jak przechowywać różne rodzaje informacji. Ale co, jeśli chcemy coś z tymi danymi zrobić? Dodać liczby, porównać teksty, sprawdzić warunki? Do tego służą operatory!
Co to jest operator?
Wyobraź sobie, że operator to symbol lub słowo kluczowe, które wykonuje jakąś operację na jednej lub więcej wartościach (zwanych operandami). To trochę jak znaki matematyczne w szkole (+,−,×,÷) – mówią nam, co zrobić z liczbami.
W C# mamy wiele rodzajów operatorów. Przyjrzyjmy się najważniejszym z nich.
1. Operatory arytmetyczne (do liczenia)
Te operatory służą do wykonywania podstawowych działań matematycznych.
| Operator | Opis | Przykład | Wynik |
| + | Dodawanie | int a = 5 + 3; | a to 8 |
| – | Odejmowanie | int b = 10 – 4; | b to 6 |
| * | Mnożenie | int c = 2 * 6; | c to 12 |
| / | Dzielenie | double d = 10.0 / 4.0; | d to 2.5 |
| int e = 10 / 4; | e to 2 (dzielenie całkowite) | ||
| % | Reszta z dzielenia (modulo) | int f = 10 % 3; | f to 1 (bo 10=3×3+1) |
Ważne o dzieleniu (/):
- Jeśli dzielisz dwie liczby całkowite (typu
int), wynikiem zawsze będzie liczba całkowita (część po przecinku zostanie odcięta). - Jeśli chcesz uzyskać wynik z częścią dziesiętną, użyj liczb zmiennoprzecinkowych (np.
doublelubfloat).
Przykład:
using System;
class Program
{
static void Main()
{
int liczba1 = 15;
int liczba2 = 4;
// Dodawanie
int suma = liczba1 + liczba2; // suma = 19
Console.WriteLine($"Suma: {suma}");
// Odejmowanie
int roznica = liczba1 - liczba2; // roznica = 11
Console.WriteLine($"Różnica: {roznica}");
// Mnożenie
int iloczyn = liczba1 * liczba2; // iloczyn = 60
Console.WriteLine($"Iloczyn: {iloczyn}");
// Dzielenie całkowite
int ilorazCalkowity = liczba1 / liczba2;
// ilorazCalkowity = 3
Console.WriteLine($"Iloraz całkowity: {ilorazCalkowity}");
// Dzielenie zmiennoprzecinkowe (musimy skonwertować jedną z liczb na double)
double ilorazDokladny = (double)liczba1 / liczba2;
// ilorazDokladny = 3.75
Console.WriteLine($"Iloraz dokładny: {ilorazDokladny}");
// Reszta z dzielenia
int reszta = liczba1 % liczba2; // reszta = 3
Console.WriteLine($"Reszta z dzielenia: {reszta}");
}
}
2. Operatory przypisania (do zapisywania wartości)
Operator przypisania (=) już znasz – używasz go do nadawania wartości zmiennym. Ale istnieją też skrócone wersje, które łączą operację arytmetyczną z przypisaniem.
| Operator | Opis | Przykład | Jest to samo co |
| #ERROR! | Proste przypisanie | int x = 10; | x staje się 10 |
| += | Dodaj i przypisz | x += 5; | x = x + 5; (dodaj 5 do x) |
| -= | Odejmij i przypisz | x -= 2; | x = x – 2; (odejmij 2 od x) |
| *= | Pomnóż i przypisz | x *= 3; | x = x * 3; (pomnóż x przez 3) |
| /= | Podziel i przypisz | x /= 2; | x = x / 2; (podziel x przez 2) |
| %= | Reszta z dzielenia i przypisz | x %= 4; | x = x % 4; (oblicz resztę i przypisz do x) |
Przykład:
using System;
class Program
{
static void Main()
{
int punkty = 100;
Console.WriteLine($"Początkowe punkty: {punkty}"); //
Początkowe punkty: 100
punkty += 50; // punkty = punkty + 50; czyli punkty = 150
Console.WriteLine($"Punkty po dodaniu: {punkty}"); //
Punkty po dodaniu: 150
punkty -= 20; // punkty = punkty - 20; czyli punkty = 130
Console.WriteLine($"Punkty po odjęciu: {punkty}"); //
Punkty po odjęciu: 130
punkty *= 2; // punkty = punkty * 2; czyli punkty = 260
Console.WriteLine($"Punkty po pomnożeniu: {punkty}"); //
Punkty po pomnożeniu: 260
punkty /= 10; // punkty = punkty / 10; czyli punkty = 26
Console.WriteLine($"Punkty po podzieleniu: {punkty}"); //
Punkty po podzieleniu: 26
}
}
3. Operatory inkrementacji i dekrementacji (szybkie +/- 1)
Służą do zwiększania lub zmniejszania wartości zmiennej o jeden.
| Operator | Opis | Przykład | Jest to samo co |
| ++ | Zwiększenie o 1 (inkrementacja) | x++; | x = x + 1; lub x += 1; |
| — | Zmniejszenie o 1 (dekrementacja) | x–; | x = x – 1; lub x -= 1; |
Pre-inkrementacja/dekrementacja vs Post-inkrementacja/dekrementacja
To trochę bardziej zaawansowane, ale ważne!
++x(pre-inkrementacja): Najpierw zwiększa wartośćxo 1, a potem używa nowej wartości.x++(post-inkrementacja): Najpierw używa obecnej wartościx, a potem zwiększaxo 1.
Analogicznie działa to dla --.
Przykład:
using System;
class Program
{
static void Main()
{
int i = 5;
Console.WriteLine($"Początkowe i: {i}"); // 5
// Post-inkrementacja: użyj, a potem zwiększ
int j = i++;
Console.WriteLine($"Po j = i++ : j={j}, i={i}"); // j=5,
i=6
int k = 10;
Console.WriteLine($"Początkowe k: {k}"); // 10
// Pre-inkrementacja: zwiększ, a potem użyj
int l = ++k;
Console.WriteLine($"Po l = ++k : l={l}, k={k}"); // l=11,
k=11
}
}
4. Operatory porównania (do sprawdzania równości/różnic)
Te operatory służą do porównywania dwóch wartości. Zawsze zwracają wartość logiczną (bool): true (prawda) lub false (fałsz). Są bardzo ważne w instrukcjach warunkowych (np. if, które poznamy później).
| Operator | Opis | Przykład | Wynik (jeśli a=5, b=10) |
| #ERROR! | Jest równe | a == b | FALSE |
| != | Jest różne | a != b | TRUE |
| > | Jest większe niż | a > b | FALSE |
| < | Jest mniejsze niż | a < b | TRUE |
| >= | Jest większe lub równe niż | a >= b | FALSE |
| <= | Jest mniejsze lub równe niż | a <= b | TRUE |
Zobaczmy to w przykładzie:
using System;
class Program
{
static void Main()
{
int wiekUcznia = 16;
int wymaganyWiek = 18;
bool czyPelnoletni = wiekUcznia >= wymaganyWiek;
Console.WriteLine($"Czy uczeń jest pełnoletni? {czyPelnoletni}"); // false
string imie1 = "Adam";
string imie2 = "adam";
string imie3 = "Adam";
bool czyImionaTakieSame = (imie1 == imie2); // Porównuje
wielkość liter!
Console.WriteLine($"Czy Adam == adam? {czyImionaTakieSame}"); // false
bool czyImionaTakieSame2 = (imie1 == imie3);
Console.WriteLine($"Czy Adam == Adam? {czyImionaTakieSame2}"); // true
}
}
Pamiętaj: == to operator porównania (czy coś jest równe czemuś), natomiast = to operator przypisania (nadaj wartość). To częsty błąd początkujących!
5. Operatory logiczne (do łączenia warunków)
Te operatory pozwalają łączyć lub negować wyniki operatorów porównania. Również zwracają wartość bool.
| Operator | Opis | Przykład | Wynik (jeśli x=5, y=10) |
| && | AND (i) | x > 0 && y > 0 | true (bo oba warunki są prawdziwe) |
| ` | ` | OR (lub) | `x > 10 |
| ! | NOT (negacja/nie) | !(x == y) | true (bo x == y jest fałszem, a ! go neguje) |
Wyjaśnienie:
&&(AND): Wynik jesttruetylko wtedy, gdy wszystkie połączone warunki sątrue. Jeśli choć jeden jestfalse, cały wynik tofalse.||(OR): Wynik jesttrue, jeśli choć jeden z połączonych warunków jesttrue. Wynik jestfalsetylko wtedy, gdy wszystkie warunki sąfalse.!(NOT): Zmienia wartość logiczną na przeciwną (truenafalse,falsenatrue).
Przykład:
using System;
class Program
{
static void Main()
{
int wiek = 18;
bool maPrawoJazdy = true;
bool maSamochod = false;
// Czy może prowadzić? (jest
pełnoletni ORAZ ma prawo jazdy)
bool mozeProwadzic = (wiek >= 18 && maPrawoJazdy);
Console.WriteLine($"Czy może prowadzić? {mozeProwadzic}"); // true
// Czy może jechać na wakacje?
(ma prawo jazdy LUB ma samochód)
bool mozeJechaNaWakacje = (maPrawoJazdy || maSamochod);
Console.WriteLine($"Czy może jechać na wakacje? {mozeJechaNaWakacje}"); // true
// Czy NIE ma samochodu?
bool nieMaSamochodu = !maSamochod;
Console.WriteLine($"Czy nie ma samochodu? {nieMaSamochodu}"); // true
}
}
Podsumowanie Operatorów:
| Rodzaj operatora | Co robi? | Przykłady |
| Arytmetyczne | Obliczenia liczbowe | +, -, *, /, % |
| Przypisania | Nadaje wartość zmiennej | #ERROR! |
| Inkrementacji/ Dekrementacji | Zwiększa/zmniejsza o 1 | ++, — |
| Porównania | Porównuje wartości, zwraca true/false | #ERROR! |
| Logiczne | Łączy warunki logiczne | && (AND), ` |
Zadania na podsumowanie.
Teraz czas na praktykę! Użyj operatorów, aby rozwiązać te proste zadania.
Zadanie 1 – Prosty kalkulator Napisz program, który:
- Pyta użytkownika o pierwszą liczbę całkowitą.
- Pyta użytkownika o drugą liczbę całkowitą.
- Wyświetla sumę tych liczb, różnicę, iloczyn, iloraz (dokładny, jako liczba zmiennoprzecinkowa!) i resztę z dzielenia.
Przykład działania:
Podaj pierwszą liczbę: 10
Podaj drugą liczbę: 3
Suma: 13
Różnica: 7
Iloczyn: 30
Iloraz: 3.3333333333333335
Reszta z dzielenia: 1
Zadanie 2 – Stan baterii Napisz program, który:
- Pyta użytkownika o aktualny poziom baterii (np.
85, czyli 85%). - Pyta, czy telefon jest podłączony do ładowarki (odpowiedzi:
taklubnie). - Wyświetla komunikat:
- „Telefon jest naładowany!” jeśli bateria jest równa lub większa niż 90% LUB jest podłączony do ładowarki.
- „Telefon wymaga ładowania.” w przeciwnym wypadku.
Wskazówka: Do pytania o ładowarkę użyj Console.ReadLine() i porównaj wynik (string!). Pamiętaj o konwersji tekstu na liczbę dla poziomu baterii.
Zadanie 3 – Punkty w grze Napisz program, który symuluje zdobywanie punktów w prostej grze:
- Zadeklaruj zmienną
int punkty = 0;. - Dodaj do
punktywartość100używając operatora+=. - Następnie zwiększ
punktyo1używając operatora++. - Wyświetl aktualną liczbę punktów.
- Odejmij
25punktów używając operatora-=. - Wyświetl nową liczbę punktów.
Lekcja 5. Instrukcje warunkowe (decyzje w programie)
W poprzedniej lekcji poznaliśmy operatory, które pozwalają nam wykonywać obliczenia i porównywać wartości. Ale co, jeśli chcemy, żeby nasz program reagował inaczej w zależności od tego, jaki jest wynik tych porównań? Na przykład, żeby wyświetlał „Witaj, dorosły!”, jeśli wiek jest większy niż 18, a „Witaj, młodzieńcze!” w innym przypadku?
Do tego służą instrukcje warunkowe! To one sprawiają, że program potrafi podejmować „decyzje” i wykonywać różne bloki kodu w zależności od spełnienia określonych warunków.
Co to jest instrukcja warunkowa?
Wyobraź sobie, że instrukcja warunkowa to trochę jak rozwidlenie drogi z tabliczkami: „Jeśli pada deszcz, idź tą drogą. W przeciwnym razie idź inną.”
W programowaniu instrukcje warunkowe pozwalają nam określić, że jeśli pewien warunek jest prawdziwy, to wykonaj jeden zestaw instrukcji, a w przeciwnym razie (jeśli warunek jest fałszywy) – wykonaj inny zestaw instrukcji.
1. Instrukcja if (Jeśli coś)
To najbardziej podstawowa instrukcja warunkowa. Pozwala wykonać dany kod tylko wtedy, gdy określony warunek jest prawdziwy (true).
Schemat działania:
if (WARUNEK)
{
// Ten kod zostanie wykonany TYLKO jeśli WARUNEK jest prawdziwy
}
if: Słowo kluczowe oznaczające początek instrukcji warunkowej.(WARUNEK): W nawiasach podajesz warunek logiczny, czyli wyrażenie, które zwracatrue(prawda) lubfalse(fałsz). Najczęściej używasz tutaj operatorów porównania (==,>,<itp.) i operatorów logicznych (&&,||,!).{ ... }: Blok kodu w nawiasach klamrowych zostanie wykonany tylko wtedy, gdy warunek jest prawdziwy. Jeśli warunek jest fałszywy, ten blok kodu zostanie pominięty.
Przykład:
using System;
class Program
{
static void Main()
{
int temperatura = 25;
// Jeśli temperatura jest większa niż 20, wyświetl komunikat o cieple
if (temperatura > 20)
{
Console.WriteLine("Jest ciepło!");
}
Console.WriteLine("Koniec sprawdzania temperatury.");
// Jeśli temperatura byłaby np. 15, komunikat "Jest ciepło!" by się nie wyświetlił.
}
}
2. Instrukcja if-else (Jeśli coś, w przeciwnym razie coś innego)
Co, jeśli chcemy wykonać coś innego, gdy warunek jest fałszywy? Do tego służy else (w przeciwnym razie).
Schemat działania:
if (WARUNEK)
{
// Ten kod zostanie wykonany, jeśli WARUNEK jest prawdziwy
}
else
{
// Ten kod zostanie wykonany, jeśli WARUNEK jest fałszywy (czyli "w przeciwnym razie")
}
Przykład:
using System;
class Program
{
static void Main()
{
int wiek = 17;
if (wiek >= 18) // Sprawdzamy, czy wiek jest 18 lub więcej
{
Console.WriteLine("Jesteś pełnoletni!");
}
else // W przeciwnym razie (czyli wiek jest mniejszy niż 18)
{
Console.WriteLine("Jesteś niepełnoletni.");
}
Console.WriteLine("Dziękujemy za sprawdzenie wieku.");
}
}
3. Instrukcja if-else if-else (Wiele możliwości)
A co, jeśli mamy więcej niż dwa możliwe scenariusze? Na przykład, chcemy ocenić wynik egzaminu: „Znakomicie”, „Dobrze”, „Dostatecznie” lub „Poprawka”. Możemy to zrobić, łącząc ze sobą instrukcje if i else if.
Schemat działania:
if (PIERWSZY_WARUNEK)
{
// Ten kod, jeśli PIERWSZY_WARUNEK jest prawdziwy
}
else if (DRUGI_WARUNEK) // Sprawdzamy ten, TYLKO jeśli PIERWSZY_WARUNEK był fałszywy
{
// Ten kod, jeśli DRUGI_WARUNEK jest prawdziwy
}
else if (TRZECI_WARUNEK) // Sprawdzamy ten, TYLKO jeśli PIERWSZY i DRUGI były fałszywe
{
// Ten kod, jeśli TRZECI_WARUNEK jest prawdziwy
}
else // Jeśli ŻADEN z powyższych warunków nie był prawdziwy
{
// Ten kod zostanie wykonany
}
Ważne: Program sprawdzi warunki po kolei. Jak tylko znajdzie pierwszy warunek, który jest prawdziwy, wykona odpowiadający mu blok kodu i zakończy całą sekwencję if-else if-else. Pozostałe warunki nie będą już sprawdzane!
Przykład:
using System;
class Program
{
static void Main()
{
int wynikEgzaminu = 75; // Wynik w procentach
if (wynikEgzaminu >= 90)
{
Console.WriteLine("Ocena: Znakomicie!");
}
else if (wynikEgzaminu >= 70) // Czyli wynik jest >=70 ALE <90
{
Console.WriteLine("Ocena: Dobrze!");
}
else if (wynikEgzaminu >= 50) // Czyli wynik jest >=50 ALE <70
{
Console.WriteLine("Ocena: Dostatecznie.");
}
else // Czyli wynik jest mniejszy niż 50
{
Console.WriteLine("Ocena: Poprawka!");
}
Console.WriteLine("Sprawdzanie ocen zakończone.");
}
}
4. Instrukcja switch (Wybór z listy)
Instrukcja switch to alternatywa dla długich łańcuchów if-else if, gdy chcemy sprawdzić jedną zmienną pod kątem wielu konkretnych wartości. Działa najlepiej, gdy masz do porównania proste typy, takie jak liczby całkowite, znaki (char) lub tekst (string).
Schemat działania:
switch (ZMIENNA_DO_SPRAWDZENIA)
{
case WARTOSC1:
// Kod do wykonania, jeśli ZMIENNA_DO_SPRAWDZENIA jest
równa WARTOSC1
break; // Ważne! Kończy działanie switch
case WARTOSC2:
// Kod do wykonania, jeśli ZMIENNA_DO_SPRAWDZENIA jest
równa WARTOSC2
break;
case WARTOSC3:
// Kod do wykonania, jeśli ZMIENNA_DO_SPRAWDZENIA jest
równa WARTOSC3
break;
default: // Opcjonalnie: Jeśli zmienna nie pasuje do żadnego
z case'ów
// Kod do wykonania w każdym innym przypadku
break;
}
switch (ZMIENNA_DO_SPRAWDZENIA): W nawiasach podajesz zmienną, której wartość chcesz porównywać.case WARTOSC:: Określa konkretną wartość. Jeśli zmienna pasuje do tej wartości, kod podcasezostanie wykonany.break;: Jest bardzo ważny! Powoduje wyjście z instrukcjiswitch. Jeśli go zabraknie, program będzie kontynuował wykonywanie kodu w następnychcase’ach (tzw. „fall-through”), co rzadko jest pożądane.default:: Jest opcjonalny. Kod wdefaultzostanie wykonany, jeśli wartość zmiennej nie pasuje do żadnego zcase’ów. Działa podobnie doelsewif-else.
Przykład:
using System;
class Program
{
static void Main()
{
char wyborUzytkownika = 'B';
Console.Write("Wybrano opcję: ");
switch (wyborUzytkownika)
{
case 'A':
Console.WriteLine("Opcja A.");
break;
case 'B':
Console.WriteLine("Opcja B. Super wybór!");
break;
case 'C':
Console.WriteLine("Opcja C.");
break;
default:
Console.WriteLine("Nieznana opcja.");
break;
}
Console.WriteLine("Koniec wyboru.");
}
}
A tu Case ze zmienną:
string imie = "Ania";
switch (imie)
{
case "Ania": Console.WriteLine("Cześć Aniu!"); break;
case "Tomek": Console.WriteLine("Hej Tomku!"); break;
default: Console.WriteLine("Cześć!"); break;
}
Podsumowanie instrukcji warunkowych:
| Instrukcja | Kiedy używamy? | Przykład (ogólny) |
| if | Jeśli kod ma być wykonany TYLKO gdy warunek jest prawdziwy. | if (warunek) { … } |
| if-else | Gdy są DWA scenariusze: jeden dla true, drugi dla false. | if (warunek) { … } else { … } |
| if-else if-else | Gdy mamy WIELE scenariuszy i sprawdzamy je po kolei. | if (…) { … } else if (…) { … } else { … } |
| switch | Gdy sprawdzamy JEDNĄ zmienną pod kątem WIELU konkretnych wartości. | switch (zmienna) { case X: … break; default: … } |
Zadania na podsumowanie.
Użyj poznanych instrukcji warunkowych, aby rozwiązać poniższe zadania:
Zadanie 1 – Sprawdzanie parzystości Napisz program, który:
- Prosi użytkownika o podanie liczby całkowitej.
- Sprawdza, czy liczba jest parzysta czy nieparzysta.
- Wskazówka: Liczba jest parzysta, jeśli reszta z dzielenia przez 2 wynosi 0 (
%operator!).
- Wskazówka: Liczba jest parzysta, jeśli reszta z dzielenia przez 2 wynosi 0 (
- Wyświetla odpowiedni komunikat, np. „Liczba 7 jest nieparzysta.” lub „Liczba 10 jest parzysta.”
Zadanie 2 – Rabat w sklepie Napisz program, który:
- Pyta użytkownika o kwotę zakupu (np.
double kwota = ...). - Zastosuj następujące zasady rabatowe:
- Jeśli kwota zakupu jest większa lub równa
200 zł, udziel15%rabatu. - Jeśli kwota zakupu jest większa lub równa
100 zł, udziel10%rabatu. - W przeciwnym razie (kwota mniejsza niż
100 zł), nie udzielaj rabatu.
- Jeśli kwota zakupu jest większa lub równa
- Wyświetl informację o zastosowanym rabacie (w procentach) oraz ostateczną kwotę do zapłaty.
Przykład działania:
Podaj kwotę zakupu: 150
Zastosowano rabat: 10%
Do zapłaty: 135 zł
Zadanie 3 – Dzień tygodnia Napisz program, który:
- Prosi użytkownika o podanie numeru dnia tygodnia (od 1 do 7, gdzie 1 to poniedziałek, 7 to niedziela).
- Używając instrukcji
switch, wyświetla nazwę dnia tygodnia. - Jeśli użytkownik poda numer spoza zakresu 1-7, wyświetl komunikat „Nieprawidłowy numer dnia.”
Przykład działania:
Podaj numer dnia tygodnia (1-7): 3
Dziś jest Środa.
Z konsoli do UI
W WinForms/WPF/MAUI warunki działają identycznie. Różni się tylko wejście/wyjście:
- zamiast
Console.ReadLine()czytasz zTextBox/Entry, - zamiast
Console.WriteLine()ustawiaszLabel.Text/TextBlock.Text.
Logikaif / else if / elsezostaje bez zmian.
Lekcja 6. Pętle (Powtarzanie zadań)
W poprzednich lekcjach nauczyliśmy się, jak przechowywać dane w zmiennych i jak program może podejmować decyzje za pomocą instrukcji warunkowych. Ale co, jeśli chcemy wykonać ten sam fragment kodu wiele razy? Na przykład, wyświetlić liczby od 1 do 100, przetworzyć listę 1000 klientów, albo grać w grę, dopóki gracz nie przegra?
Pisanie tego samego kodu raz po raz byłoby bardzo żmudne i podatne na błędy. Na szczęście istnieją pętle!
Co to jest pętla?
Wyobraź sobie, że pętla to jak automat do powtarzania zadań. Dajesz mu instrukcję, a on wykonuje ją określoną liczbę razy lub tak długo, aż pewien warunek zostanie spełniony. Zamiast mówić „podnieś lewą nogę, opuść lewą nogę, podnieś prawą nogę, opuść prawą nogę…” sto razy, po prostu mówisz „idź naprzód 100 kroków”.
W programowaniu pętle pozwalają nam wielokrotnie wykonywać ten sam blok kodu, co oszczędza czas, zmniejsza ilość kodu i sprawia, że programy są bardziej elastyczne.
W C# mamy kilka rodzajów pętli, każda do nieco innych zastosowań. Poznajmy najważniejsze!
1. Pętla for (Ile razy?)
Pętla for jest idealna, gdy wiemy z góry, ile razy chcemy powtórzyć jakąś operację. Najczęściej używa się jej do iterowania (przechodzenia) przez sekwencje liczb.
Schemat działania:
for (INICJALIZACJA; WARUNEK_KONTYNUACJI; KROK_PO_KAZDEJ_ITERACJI)
{
// Kod wewnątrz pętli - będzie wykonany w każdym powtórzeniu
}
INICJALIZACJA: Dzieje się tylko raz na początku pętli. Zazwyczaj tutaj deklarujemy i inicjalizujemy zmienną liczącą (np.int i = 0;).WARUNEK_KONTYNUACJI: Ten warunek jest sprawdzany przed każdym powtórzeniem pętli. Jeśli warunek jest prawdziwy (true), pętla kontynuuje działanie. Jeśli jest fałszywy (false), pętla się zatrzymuje.KROK_PO_KAZDEJ_ITERACJI: Dzieje się po każdym wykonaniu bloku kodu w pętli. Najczęściej jest to zwiększenie lub zmniejszenie zmiennej liczącej (np.i++lubi--).
Przykład: Liczenie od 1 do 5
using System;
class Program
{
static void Main()
{
Console.WriteLine("Liczymy od 1 do 5:");
// int i = 1; -> Startujemy od 1
// i <= 5; -> Kontynuujemy, dopóki i jest mniejsze lub równe 5
// i++ -> Po każdym powtórzeniu zwiększamy i o 1
for (int i = 1; i <= 5; i++)
{
Console.WriteLine(i); // Wypisze: 1, 2, 3, 4, 5
}
Console.WriteLine("\nLiczymy co 2 od 0 do 10:");
for (int j = 0; j <= 10; j += 2) // Zwiększamy j o 2 w każdym kroku
{
Console.WriteLine(j); // Wypisze: 0, 2, 4, 6, 8, 10
}
Console.WriteLine("\nOdliczanie od 3 do 1:");
for (int k = 3; k >= 1; k--) // Zmniejszamy k o 1 w każdym kroku
{
Console.WriteLine(k); // Wypisze: 3, 2, 1
}
}
}
2. Pętla while (Dopóki coś)
Pętla while jest używana, gdy chcemy powtarzać kod tak długo, jak pewien warunek jest prawdziwy. Nie wiemy z góry, ile razy pętla się wykona.
Schemat działania:
while (WARUNEK_KONTYNUACJI)
{
// Kod wewnątrz pętli - będzie wykonany, dopóki WARUNEK_KONTYNUACJI jest prawdziwy
// Ważne: Wewnątrz pętli musi być coś, co w końcu zmieni WARUNEK_KONTYNUACJI na false,
// inaczej pętla będzie działać w nieskończoność (nieskończona pętla)!
}
while: Słowo kluczowe oznaczające pętlę.(WARUNEK_KONTYNUACJI): Ten warunek jest sprawdzany przed każdym powtórzeniem. Jeśli jesttrue, kod w bloku{}się wykona. Jeślifalse, pętla się zatrzymuje.
Przykład: Zgadywanie liczby
using System;
class Program
{
static void Main()
{
Random losowaLiczba = new Random(); // Tworzymy obiekt do losowania liczb
int szukanaLiczba = losowaLiczba.Next(1, 11); // Losujemy liczbę od 1 do 10
int zgadnietaLiczba = 0;
int proby = 0;
Console.WriteLine("Zgadnij liczbę od 1 do 10!");
// Dopóki zgadniętaLiczba nie jest równa szukanaLiczba
while (zgadnietaLiczba != szukanaLiczba)
{
Console.Write("Twoja próba: ");
string input = Console.ReadLine();
zgadnietaLiczba = int.Parse(input); // Konwertujemy tekst na liczbę
proby++;
if (zgadnietaLiczba < szukanaLiczba)
{
Console.WriteLine("Za mało!");
}
else if (zgadnietaLiczba > szukanaLiczba)
{
Console.WriteLine("Za dużo!");
}
}
Console.WriteLine($"Gratulacje! Zgadłeś liczbę {szukanaLiczba} w {proby} próbach.");
}
}
3. Pętla do-while (Wykonaj raz, potem dopóki coś)
Pętla do-while jest podobna do while, ale ma jedną kluczową różnicę: blok kodu w {} zostanie wykonany przynajmniej raz, zanim warunek zostanie sprawdzony.
Schemat działania:
do
{
// Kod wewnątrz pętli - zostanie wykonany przynajmniej raz
} while (WARUNEK_KONTYNUACJI); // Warunek sprawdzany JUZ PO wykonaniu bloku
do: Rozpoczyna blok kodu, który zawsze wykona się przynajmniej raz.while (WARUNEK_KONTYNUACJI);: Warunek jest sprawdzany na końcu. Jeśli jesttrue, pętla powtarza się. Jeślifalse, zatrzymuje się.
Przykład: Proste menu z potwierdzeniem
using System;
class Program
{
static void Main()
{
string wybor;
do
{
Console.WriteLine("--- MENU ---");
Console.WriteLine("1. Nowa gra");
Console.WriteLine("2. Wczytaj grę");
Console.WriteLine("3. Opcje");
Console.WriteLine("4. Wyjście");
Console.Write("Wybierz opcję (1-4): ");
wybor = Console.ReadLine(); // Pobieramy wybór użytkownika
if (wybor == "1") Console.WriteLine("Rozpoczynam nową grę...");
else if (wybor == "2") Console.WriteLine("Wczytuję grę...");
else if (wybor == "3") Console.WriteLine("Otwieram opcje...");
else if (wybor == "4") Console.WriteLine("Wychodzę z gry. Do zobaczenia!");
else Console.WriteLine("Nieznany wybór, spróbuj ponownie.");
// Pętla będzie działać, dopóki użytkownik nie wybierze opcji '4'
} while (wybor != "4");
Console.WriteLine("Program zakończony.");
}
}
4. Pętla foreach (Dla każdego elementu kolekcji)
Pętla foreach jest bardzo wygodna, gdy chcemy przejść przez każdy element w kolekcji (np. liście tekstów, tablicy liczb itp.) bez konieczności ręcznego zarządzania indeksami. Poznamy ją lepiej, gdy wprowadzimy tablice i listy, ale warto o niej wspomnieć już teraz.
Schemat działania:
foreach (TYP_ELEMENTU NAZWA_ZMIENNEJ_ELEMENTU in KOLEKCJA)
{
// Kod wewnątrz pętli - wykonuje się dla każdego elementu z KOLEKCJI
}
Przykład: Wyświetlanie imion
using System;
class Program
{
static void Main()
{
string[] imiona = { "Ania", "Bartek", "Celina", "Dawid" }; // To jest prosta kolekcja (tablica) tekstów
Console.WriteLine("Lista imion:");
// Dla każdego 'imie' typu 'string' w kolekcji 'imiona'
foreach (string imie in imiona)
{
Console.WriteLine($"- {imie}");
}
}
}
break i continue w pętlach (Sterowanie przepływem)
Czasem chcemy specjalnie sterować pętlą:
break;: Całkowicie przerywa działanie najbliższej pętli i kontynuuje wykonywanie kodu poza pętlą.continue;: Przerywa tylko aktualne powtórzenie pętli i przechodzi do następnego powtórzenia.
Przykład:
using System;
class Program
{
static void Main()
{
Console.WriteLine("Przykład z 'break':");
for (int i = 1; i <= 10; i++)
{
if (i == 5)
{
Console.WriteLine("Znaleziono 5! Przerywam pętlę.");
break; // Pętla zakończy się tutaj, nie wyświetli 6, 7, ...
}
Console.WriteLine(i);
}
Console.WriteLine("Pętla z 'break' zakończona.\n");
Console.WriteLine("Przykład z 'continue':");
for (int i = 1; i <= 5; i++)
{
if (i == 3)
{
Console.WriteLine("Pomiń liczbę 3.");
continue; // Pomiń resztę kodu w tym powtórzeniu i przejdź do następnego 'i'
}
Console.WriteLine(i); // Nie wyświetli 3
}
Console.WriteLine("Pętla z 'continue' zakończona.");
}
}
Podsumowanie Pętli:
| Pętla | Kiedy używamy? | Jak działa? |
| for | Gdy wiemy, ile razy chcemy powtórzyć operację. | Inicjalizacja, warunek sprawdzany przed, krok po. |
| while | Gdy powtarzamy, dopóki warunek jest prawdziwy. Nie wiemy, ile razy się wykona. | Warunek sprawdzany przed każdym powtórzeniem. |
| do-while | Gdy chcemy, aby kod wykonał się przynajmniej raz, a potem dopóki warunek jest prawdziwy. | Kod wykonany raz, potem warunek sprawdzany po każdym powtórzeniu. |
| foreach | Gdy chcemy przejść przez każdy element w kolekcji (np. tablicy, liście). | Automatycznie przechodzi przez wszystkie elementy. |
Zadania na podsumowanie.
Teraz czas na praktykę z pętlami!
Zadanie 1 – Tabliczka mnożenia Napisz program, który:
- Prosi użytkownika o podanie liczby całkowitej (np. 7).
- Używając pętli
for, wyświetla tabliczkę mnożenia dla tej liczby od 1 do 10.
Przykład działania (dla liczby 7):
Podaj liczbę dla tabliczki mnożenia: 7
7 x 1 = 7
7 x 2 = 14
...
7 x 10 = 70
Zadanie 2 – Sumowanie liczb Napisz program, który:
- Prosi użytkownika o podawanie liczb całkowitych.
- Program sumuje podane liczby.
- Pętla ma działać tak długo, aż użytkownik wpisze
0. Wtedy program ma zakończyć sumowanie i wyświetlić ostateczną sumę.- Wskazówka: Użyj pętli
whilelubdo-while.
- Wskazówka: Użyj pętli
Przykład działania:
Podaj liczbę (0 kończy): 5
Podaj liczbę (0 kończy): 12
Podaj liczbę (0 kończy): -3
Podaj liczbę (0 kończy): 0
Suma wszystkich liczb wynosi: 14
Zadanie 3 – Sprawdzanie PIN-u Napisz program, który:
- Definiuje poprawny PIN jako zmienną
string poprawnyPIN = "1234";. - Daje użytkownikowi 3 próby na wpisanie poprawnego PIN-u.
- Jeśli użytkownik wpisze poprawny PIN, wyświetl „Dostęp przyznany!” i przerwij pętlę (
break). - Jeśli użytkownik wykorzysta wszystkie 3 próby i nie wpisze poprawnego PIN-u, wyświetl „Konto zablokowane!”.
Wskazówka: Użyj pętli for (do liczenia prób) i instrukcji if-else wewnątrz pętli.
Lekcja 7. Funkcje i Metody (Budowanie własnych narzędzi)
W dotychczasowych lekcjach pisaliśmy cały kod w jednej, głównej metodzie Main(). Nasze programy były proste, więc to wystarczało. Ale wyobraź sobie, co by było, gdyby program miał setki, a nawet tysiące linijek kodu! Robiłby się straszny bałagan, a odnalezienie i poprawienie czegoś byłoby koszmarem.
Na szczęście w programowaniu mamy funkcje (w C# częściej nazywane metodami), które pomagają nam organizować kod.
Wspólna logika dla konsoli, desktopu i MAUI
Dobrą praktyką jest umieścić obliczenia w osobnej klasie, np. public static class Obliczenia { ... }.
Potem:
MAUI wywołuje je z komend (ICommand) w ViewModelu.
Ten sam kod – trzy fronty. Konsola wywołuje metody bezpośrednio,
WinForms/WPF wywołuje je w obsłudze zdarzeń przycisków,
Co to jest funkcja/metoda?
Wyobraź sobie, że funkcja (metoda) to taki mały, wyspecjalizowany robot, który potrafi wykonać konkretne zadanie. Dajesz mu zadanie do wykonania (możesz mu coś przekazać, co jest potrzebne do pracy), a on to wykonuje i, ewentualnie, zwraca Ci wynik.
Na przykład:
- Robot „DodajDwieLiczby”: dajesz mu 5 i 3, a on zwraca 8.
- Robot „WyswietlPowitanie”: dajesz mu imię „Ania”, a on wyświetla „Witaj, Ania!”.
W programowaniu metoda to blok kodu, który wykonuje określone zadanie. Dzięki metodom:
- Organizujemy kod: Dzielimy duży program na mniejsze, łatwiejsze do zarządzania części.
- Unikamy powtarzania kodu: Raz napisaną metodę możemy wywoływać wiele razy w różnych miejscach programu.
- Ułatwiamy debugowanie: Łatwiej znaleźć błąd w małej metodzie niż w całym, długim kodzie.
- Może przyjmować dane wejściowe (tzw. parametry)
- Może zwracać wynik działania (przy pomocy słowa kluczowego return)
- Łatwia naprawę błędów.
Składnia metody w C#
Każda metoda ma swoją „wizytówkę”, która określa, jak się nazywa, co przyjmuje i co zwraca.
modyfikator_dostepu static typ_zwracany NazwaMetody(typ1 parametr1, typ2 parametr2, ...)
{
// Ciało metody - tutaj piszemy kod, który wykonuje to zadanie
}
Rozłóżmy to na części:
modyfikator_dostepu: Na razie będziemy używaćpublic(dostępna zewsząd) lub pominiemy go (domyślnieprivate). To bardziej zaawansowany temat związany z programowaniem obiektowym.static: Na początku, wszystkie nasze metody będąstatic. Oznacza to, że metoda należy do klasy, a nie do konkretnego obiektu tej klasy. Dzięki temu możesz ją wywołać bezpośrednio, np.Program.Main()alboConsole.WriteLine(). To też temat na przyszłość, ale na razie po prostu go używamy.typ_zwracany: Określa, co metoda zwróci po zakończeniu swojej pracy.- Jeśli metoda nie zwraca żadnej wartości (np. tylko coś wyświetla), używamy słowa kluczowego
void. - Jeśli metoda zwraca liczbę całkowitą, użyjemy
int. - Jeśli zwraca tekst, użyjemy
string. - Jeśli zwraca wartość logiczną, użyjemy
bool. - …i tak dalej dla każdego typu danych.
- Jeśli metoda nie zwraca żadnej wartości (np. tylko coś wyświetla), używamy słowa kluczowego
NazwaMetody: To unikalna nazwa, którą sam nadajesz metodzie. Powinna być opisowa i mówić, co metoda robi (np.ObliczSume,WyswietlKomunikat).- Nazwy metod w C# zaczynają się dużą literą (konwencja PascalCase).
(typ1 parametr1, typ2 parametr2, ...): W nawiasach podajemy parametry (nazywane też argumentami). To są dane, które przekazujemy metodzie, żeby mogła wykonać swoje zadanie. Każdy parametr ma swój typ i nazwę.- Jeśli metoda nie potrzebuje żadnych danych wejściowych, nawiasy zostają puste:
().
- Jeśli metoda nie potrzebuje żadnych danych wejściowych, nawiasy zostają puste:
{ ... }: To jest ciało metody, czyli blok kodu, który zostanie wykonany, gdy metoda zostanie wywołana.
Metody bez parametrów i bez wartości zwracanej (void)
To najprostszy typ metody. Wykonuje jakieś zadanie, ale nie potrzebuje do tego dodatkowych danych i nie zwraca żadnego wyniku.
Przykład: Metoda, która wyświetla powitalny komunikat.
using System;
class Program
{
// Definicja metody WyswietlPowitanie
static void WyswietlPowitanie()
{
Console.WriteLine("Witaj w programie!");
Console.WriteLine("Miło Cię widzieć.");
}
static void Main() // To jest nasza główna metoda, która zawsze się uruchamia
{
Console.WriteLine("Zaczynam program...");
WyswietlPowitanie(); // WYWOŁANIE metody WyswietlPowitanie
Console.WriteLine("Program zakończony.");
}
}
Wyjaśnienie:
- Zdefiniowaliśmy nową metodę
WyswietlPowitanie. Jeststatic voidi nie ma parametrów. - Wewnątrz
Main()wywołaliśmy tę metodę po prostu pisząc jej nazwę i nawiasy(). - Po wywołaniu, program „przeskoczył” do kodu w
WyswietlPowitanie(), wykonał go, a potem wrócił doMain()i kontynuował od miejsca, w którym skończył.
Metody z parametrami, bez wartości zwracanej (void)
Takie metody potrzebują danych wejściowych, żeby wykonać swoje zadanie, ale same nie zwracają wyniku.
Przykład: Metoda, która wyświetla spersonalizowane powitanie.
using System;
class Program
{
// Definicja metody WyswietlPowitanieImie
// Przyjmuje jeden parametr typu string o nazwie 'imie'
static void WyswietlPowitanieImie(string imie)
{
Console.WriteLine($"Witaj, {imie}!");
Console.WriteLine("Cieszymy się, że jesteś z nami.");
}
static void Main()
{
Console.Write("Podaj swoje imię: ");
string mojeImie = Console.ReadLine();
WyswietlPowitanieImie(mojeImie); // Wywołanie metody, przekazanie zmiennej 'mojeImie' jako argumentu
WyswietlPowitanieImie("Anna"); // Możemy też przekazać bezpośrednio tekst
Console.WriteLine("Program zakończony.");
}
}
Wyjaśnienie:
- Metoda
WyswietlPowitanieImiema jeden parametr:string imie. Oznacza to, że kiedy będziesz ją wywoływać, musisz jej podać jakiś tekst. - Kiedy wywołujemy
WyswietlPowitanieImie(mojeImie);, wartość zmiennejmojeImie(np. „Krzysztof”) jest kopiowana do parametruimiewewnątrz metody. - Wewnątrz metody
imiezachowuje się jak zwykła zmienna.
Metody z wartością zwracaną (nie-void)
Te metody wykonują swoje zadanie i po zakończeniu zwracają jakiś wynik. Muszą użyć słowa kluczowego return i po nim podać wartość zgodną z typ_zwracany metody.
Przykład: Metoda, która oblicza sumę dwóch liczb i zwraca wynik.
using System;
class Program
{
// Definicja metody ObliczSume
// Przyjmuje dwa parametry typu int: 'a' i 'b'
// Zwraca wartość typu int
static int ObliczSume(int a, int b)
{
int suma = a + b;
return suma; // Zwraca wynik obliczeń
// Kod poniżej 'return' w tej samej metodzie NIE zostanie wykonany
}
// Inna metoda, która zwraca string
static string PobierzKomunikatPowitalny()
{
return "Witaj z funkcji!";
}
static void Main()
{
int liczba1 = 10;
int liczba2 = 20;
// Wywołujemy metodę ObliczSume i jej wynik (30) zapisujemy do zmiennej 'wynik'
int wynik = ObliczSume(liczba1, liczba2);
Console.WriteLine($"Suma liczb {liczba1} i {liczba2} wynosi: {wynik}"); // Wyświetli: 30
// Możemy też od razu użyć wyniku metody
Console.WriteLine($"Podwojona suma: {ObliczSume(5, 7) * 2}"); // (5+7)*2 = 24
// Użycie metody zwracającej string
string komunikat = PobierzKomunikatPowitalny();
Console.WriteLine(komunikat);
}
}
Wyjaśnienie:
- Metoda
ObliczSumemaintjakotyp_zwracany, co oznacza, że musi zwrócić liczbę całkowitą. - Instrukcja
return suma;powoduje, że wartość zmiennejsumajest „odesłana” z powrotem do miejsca, z którego metoda została wywołana. - W
Main(), gdy piszemyint wynik = ObliczSume(liczba1, liczba2);, to tak, jakbyśmy napisaliint wynik = 30;po wykonaniu metody.
Przeciążanie metod (Overloading)
W C# możemy mieć kilka metod o tej samej nazwie, pod warunkiem, że mają różne listy parametrów. Oznacza to, że mogą przyjmować inną liczbę parametrów lub parametry różnych typów. Kompilator C# sam wybierze, której wersji metody użyć, na podstawie przekazanych argumentów.
Przykład: Metoda WyswietlDane, która potrafi wyświetlać dane na różne sposoby.
using System;
class Program
{
// Metoda WyswietlDane: tylko imię
static void WyswietlDane(string imie)
{
Console.WriteLine($"Witaj, {imie}!");
}
// Metoda WyswietlDane: imię i wiek
static void WyswietlDane(string imie, int wiek)
{
Console.WriteLine($"Witaj, {imie}! Masz {wiek} lat.");
}
// Metoda WyswietlDane: wiek i wzrost (zauważ inna kolejność typów lub inna liczba typów)
static void WyswietlDane(int wiek, double wzrost)
{
Console.WriteLine($"Osoba w wieku {wiek} lat ma {wzrost} cm wzrostu.");
}
static void Main()
{
WyswietlDane("Alicja"); // Wywoła pierwszą wersję
WyswietlDane("Bartosz", 25); // Wywoła drugą wersję
WyswietlDane(30, 180.5); // Wywoła trzecią wersję
Console.WriteLine("Wszystkie dane wyświetlone.");
}
}
Wyjaśnienie: Mimo że wszystkie metody nazywają się WyswietlDane, C# wie, którą z nich wywołać, patrząc na typy i liczbę argumentów, które do niej przekazujemy.
Po co jest przeciążenie metod?
Główny cel przeciążania metod to umożliwienie tworzenia bardziej elastycznych i intuicyjnych interfejsów dla twojego kodu. Wyobraź sobie to tak:
- Intuicyjność i spójność nazw: Zamiast wymyślać różne nazwy dla metod, które robią w zasadzie to samo, ale na trochę innych danych, możesz użyć tej samej, logicznej nazwy. Na przykład, chcesz wypisać coś na konsolę. Nie musisz pamiętać, czy to
WriteLineString(),WriteLineInt(),WriteLineDouble(). Masz po prostuConsole.WriteLine(), a C# sam wie, jak obsłużyć tekst, liczbę czy inną wartość, którą mu podasz. To sprawia, że API (interfejs programistyczny) jest prostsze do zapamiętania i użycia. - Obsługa różnych typów danych: Czasem ta sama operacja musi być wykonana na różnych typach danych. Zamiast pisać
ObliczPoleKwadratu(double bok)iObliczPoleProstokata(double dlugosc, double szerokosc), możesz mieć dwie metodyObliczPole(), które C# rozróżni po parametrach. - Obsługa różnej liczby argumentów: Może potrzebujesz, żeby metoda działała zarówno wtedy, gdy podasz jej wszystkie informacje, jak i wtedy, gdy podasz tylko część, a reszta zostanie uzupełniona domyślnymi wartościami.
- Zwiększona elastyczność: Przeciążone metody pozwalają twoim funkcjom „dostosować się” do kontekstu, w którym są wywoływane, bez konieczności tworzenia zupełnie nowych nazw.
Czy przeciążenie metod jest wskazane czy trzeba go unikać?
Jest zdecydowanie wskazane i jest to dobra praktyka programistyczna, pod warunkiem, że spełnia kluczowy warunek:
- Przeciążone metody powinny wykonywać logicznie tę samą operację, nawet jeśli robią to na różnych danych wejściowych.
Kiedy jest wskazane (dobra praktyka):
- Gdy metody wykonują to samo zadanie, ale na różnych typach danych.
int Dodaj(int a, int b)double Dodaj(double a, double b)string Dodaj(string s1, string s2)(konkatenacja)- Wszystkie „dodają” w jakimś sensie.
- Gdy metody wykonują to samo zadanie, ale z różnym zestawem parametrów (np. jedne mają domyślne wartości).
void RysujKolo(int promien)void RysujKolo(int promien, string kolor)- Obie metody rysują koło, ale druga daje więcej kontroli.
- Dla przejrzystości i czytelności kodu. Ktoś, kto będzie używał twoich metod, łatwiej znajdzie funkcję, jeśli będzie miała spójną nazwę dla podobnych operacji.
Kiedy należy unikać (zła praktyka):
- Gdy przeciążone metody wykonują zupełnie różne operacje, mimo tej samej nazwy. To prowadzi do zamieszania i błędów.
int Oblicz(int a, int b)(sumuje)double Oblicz(double c, double d)(mnoży)- To jest zły przykład przeciążenia, ponieważ
Obliczw każdym przypadku robi coś innego.
Podsumowanie Funkcji i Metod:
| Element metody | Opis | Przykłady |
| static | Wskazuje, że metoda należy do klasy, nie do obiektu. Na razie używaj zawsze. | static void MojaMetoda() |
| void | Typ zwracany. Oznacza, że metoda NIC NIE ZWRACA. | static void Wyswietl() |
| typ_zwracany | Typ danych, które metoda zwróci (int, string, bool, double itd.) | static int Oblicz() |
| NazwaMetody | Unikalna nazwa, którą sam nadajesz. Zaczyna się dużą literą. | MojaFunkcja, ObliczPole |
| parametry | Dane, które przekazujemy metodzie do pracy. W nawiasach (). | (int a, string b) |
| return | Słowo kluczowe do zwracania wartości z metody (tylko w metodach nie-void). | return wynik; |
Mini-most do MVVM (WPF/MAUI)
Jeśli wchodzisz w WPF/MAUI, rozważ prosty wzorzec MVVM:
ViewModelma właściwości (Imie,Wynik) i komendy (PowitajCommand).View(XAML) wiąże kontrolki z tymi właściwościami (Binding).
Metody z tej lekcji idealnie nadają się do wywołań z komend.
Zadania na podsumowanie.
Zadanie 1 – Konwerter temperatur Napisz program, który zawiera dwie metody:
static double CelsiusNaFahrenheit(double celsius):- Przyjmuje temperaturę w stopniach Celsjusza.
- Oblicza temperaturę w stopniach Fahrenheita według wzoru:
Fahrenheit = (Celsius * 9 / 5) + 32. - Zwraca wynik jako
double.
static double FahrenheitNaCelsius(double fahrenheit):- Przyjmuje temperaturę w stopniach Fahrenheita.
- Oblicza temperaturę w stopniach Celsjusza według wzoru:
Celsius = (Fahrenheit - 32) * 5 / 9. - Zwraca wynik jako
double.
W metodzie Main():
- Poproś użytkownika o podanie temperatury w Celsjuszach, przekonwertuj ją na Fahrenheity i wyświetl wynik.
- Poproś użytkownika o podanie temperatury w Fahrenheitach, przekonwertuj ją na Celsjusze i wyświetl wynik.
Przykład działania:
Podaj temperaturę w stopniach Celsjusza: 25
25 Celsjusza to 77 Fahrenheita.
Podaj temperaturę w stopniach Fahrenheita: 68
68 Fahrenheita to 20 Celsjusza.
Zadanie 2 – Kalkulator pola figur Napisz program, który ma trzy przeciążone metody o nazwie ObliczPole:
static double ObliczPole(double bok): Oblicza pole kwadratu (przyjmuje długość boku).static double ObliczPole(double dlugosc, double szerokosc): Oblicza pole prostokąta (przyjmuje długość i szerokość).static double ObliczPole(double podstawa, double wysokosc, string typFigury): Oblicza pole trójkąta (przyjmuje podstawę i wysokość,typFigurymożesz zignorować lub użyć do wyświetlenia komunikatu).
W metodzie Main():
- Wywołaj każdą z tych metod z różnymi argumentami i wyświetl ich wyniki, jasno określając, pole jakiej figury zostało obliczone.
Przykład działania:
Pole kwadratu o boku 5 to: 25
Pole prostokąta o bokach 4x6 to: 24
Pole trójkąta o podstawie 10 i wysokości 5 to: 25
Zadanie 3 – Sprawdzenie hasła Napisz metodę static bool SprawdzHaslo(string haslo):
- Przyjmuje
stringjako hasło. - Zwraca
true, jeśli hasło jest dłuższe niż 8 znaków i zawiera cyfrę (możesz uprościć to sprawdzenie, np. tylko sprawdzić długość), lubfalsew przeciwnym razie.- Wskazówka do cyfry: Możesz użyć prostego sprawdzania, np.
haslo.Contains("1") || haslo.Contains("2")itp., albo pętliforeachpo znakach hasła ichar.IsDigit(znak). Dla uproszczenia na tym etapie wystarczy prosty warunek. *W metodzieMain():
- Wskazówka do cyfry: Możesz użyć prostego sprawdzania, np.
- Poproś użytkownika o wpisanie hasła.
- Wywołaj metodę
SprawdzHasloi na podstawie jej wyniku wyświetl komunikat „Hasło poprawne!” lub „Hasło zbyt słabe!”.
Lekcja 8. Tablice i Kolekcje (Przechowywanie wielu danych)
Do tej pory nauczyliśmy się, jak przechowywać pojedyncze wartości w zmiennych. Ale co, jeśli chcemy przechowywać wiele wartości tego samego typu? Na przykład listę imion uczniów, wyniki egzaminów, czy temperatury z całego tygodnia? Do tego właśnie służą tablice i kolekcje. Pozwalają nam gromadzić i zarządzać grupami danych w jednym miejscu.
Część 1: Tablice jednowymiarowe (Lista danych)
Co to jest tablica?
Wyobraź sobie tablicę jako szereg ponumerowanych skrytek (pudełek) obok siebie, gdzie każda skrytka może przechowywać tylko jeden rodzaj rzeczy (np. tylko liczby, tylko teksty).
W programowaniu tablica to struktura danych, która przechowuje stałą liczbę elementów tego samego typu w kolejności. Każdy element ma swój unikalny indeks (numer pozycji), zaczynający się od 0.
Deklaracja i inicjalizacja tablicy
Zanim użyjemy tablicy, musimy ją zadeklarować (podać typ i nazwę) i zainicjalizować (stworzyć i ewentualnie wypełnić danymi).
1. Deklaracja (bez podawania rozmiaru od razu):
typ_elementow[] nazwaTablicy;
Przykład: int[] liczby; (deklarujemy, że liczby to będzie tablica liczb całkowitych)
2. Inicjalizacja (tworzenie tablicy i określanie jej rozmiaru):
- Tworzenie pustej tablicy o określonym rozmiarze: C#
nazwaTablicy = new typ_elementow[rozmiar];Przykład:int[] liczby = new int[5];(tworzy tablicę na 5 liczb całkowitych)- Po stworzeniu elementy tablicy są wypełniane domyślnymi wartościami dla danego typu (np.
0dlaint,nulldlastring,falsedlabool).
- Po stworzeniu elementy tablicy są wypełniane domyślnymi wartościami dla danego typu (np.
- Tworzenie i od razu wypełnianie elementami: C#
typ_elementow[] nazwaTablicy = { wartosc1, wartosc2, wartosc3, ... };Przykład:string[] imiona = { "Anna", "Bartek", "Celina" };- W tym przypadku rozmiar tablicy jest automatycznie określany przez liczbę podanych elementów.
Przykład tworzenia tablic:
using System;
class Program
{
static void Main()
{
// Deklaracja i inicjalizacja tablicy na 3 temperatury (typ double)
double[] temperatury = new double[3];
// Domyślne wartości: 0, 0, 0
Console.WriteLine($"Temperatura 1 (domyślna): {temperatury[0]}");
// Deklaracja i inicjalizacja tablicy tekstów z od razu podanymi wartościami
string[] dniTygodnia = { "Poniedziałek", "Wtorek", "Środa", "Czwartek", "Piątek", "Sobota", "Niedziela" };
Console.WriteLine($"Pierwszy dzień tygodnia: {dniTygodnia[0]}"); // Zaczynamy od indeksu 0!
Console.WriteLine($"Ostatni dzień tygodnia: {dniTygodnia[6]}"); // Dni od 0 do 6 to 7 elementów
}
}
Dostęp do elementów tablicy
Do elementów tablicy odwołujemy się za pomocą ich indeksu (numeru pozycji) w nawiasach kwadratowych []. Pamiętaj, że indeks zawsze zaczyna się od 0!
tablica[indeks]– dostęp do elementu na danej pozycji.tablica[indeks] = nowa_wartosc;– przypisanie nowej wartości do elementu.
Ważne: Próba dostępu do indeksu, który wykracza poza rozmiar tablicy (np. temperatury[5] w tablicy o rozmiarze 3), spowoduje błąd w trakcie działania programu (IndexOutOfRangeException).
Przykład dostępu i modyfikacji:
using System;
class Program
{
static void Main()
{
int[] oceny = new int[4]; // Tablica na 4 oceny
oceny[0] = 5; // Pierwsza ocena (na indeksie 0)
oceny[1] = 4; // Druga ocena
oceny[2] = 5; // Trzecia ocena
oceny[3] = 3; // Czwarta ocena
Console.WriteLine($"Pierwsza ocena: {oceny[0]}"); // Wyświetli 5
Console.WriteLine($"Trzecia ocena: {oceny[2]}"); // Wyświetli 5
oceny[1] = 2; // Zmieniamy drugą ocenę z 4 na 2
Console.WriteLine($"Nowa druga ocena: {oceny[1]}"); // Wyświetli 2
// Rozmiar tablicy możemy sprawdzić za pomocą właściwości Length
Console.WriteLine($"Liczba ocen w tablicy: {oceny.Length}"); // Wyświetli 4
}
}
Iterowanie (przechodzenie) przez tablicę
Aby przetworzyć wszystkie elementy w tablicy, najczęściej używamy pętli.
1. Pętla for (klasyczny sposób): Najlepsza, gdy potrzebujemy znać indeks elementu lub chcemy przejść przez część tablicy.
using System;
class Program
{
static void Main()
{
string[] owoce = { "Jabłko", "Gruszka", "Śliwka", "Banan" };
Console.WriteLine("Moje ulubione owoce:");
// Pętla od indeksu 0 do (długość tablicy - 1)
for (int i = 0; i < owoce.Length; i++)
{
Console.WriteLine($"- {owoce[i]} (indeks: {i})");
}
}
}
2. Pętla foreach (najprostszy sposób): Idealna, gdy chcemy po prostu przetworzyć każdy element po kolei, bez potrzeby odwoływania się do indeksów. Jest bardzo czytelna.
using System;
class Program
{
static void Main()
{
int[] punkty = { 10, 25, 5, 30, 15 };
int sumaPunktow = 0;
Console.WriteLine("Otrzymane punkty:");
foreach (int p in punkty) // Dla każdej liczby 'p' w tablicy 'punkty'
{
Console.WriteLine($"+ {p} punktów");
sumaPunktow += p; // Dodajemy punkty do sumy
}
Console.WriteLine($"\nCałkowita suma punktów: {sumaPunktow}");
}
}
ZADANIE:
Spróbuj rozwiązać te zadania, zanim przejdziesz do kolejnej części.
Zadanie 1 – Lista zakupów Napisz program, który:
- Tworzy tablicę typu
stringo nazwielistaZakupow, która pomieści 5 elementów. - Poproś użytkownika o wpisanie 5 rzeczy, które chce kupić, i zapisz je kolejno do tablicy.
- Po zebraniu wszystkich pięciu elementów wyświetl całą listę zakupów, używając pętli
for.
Zadanie 2 – Średnia temperatura Napisz program, który:
- Tworzy tablicę typu
doubleo nazwietemperaturyTygodniai inicjalizuje ją od razu siedmioma dowolnymi wartościami (temperaturami np.18.5, 20.0, 19.2, ...). - Oblicza sumę wszystkich temperatur.
- Oblicza średnią temperaturę.
- Wyświetla sumę i średnią temperaturę. Użyj pętli
foreachdo sumowania.
Część 2: Tablice dwuwymiarowe i Kolekcje (listy i słowniki)
1. Tablice dwuwymiarowe (Tabele danych)
Tablica dwuwymiarowa to nic innego jak tablica tablic, czyli struktura do przechowywania danych w formie tabeli (wiersze i kolumny). Przydaje się, np. do przechowywania współrzędnych, plansz do gier (szachy, statki), czy macierzy.
Schemat działania:
typ_elementow[,] nazwaTablicy; // Zauważ przecinek w nawiasach kwadratowych!
Deklaracja i inicjalizacja:
typ_elementow[,] nazwaTablicy = new typ_elementow[liczba_wierszy, liczba_kolumn];
Przykład: int[,] macierz = new int[3, 3]; (tworzy macierz 3×3)
Dostęp do elementów: Odwołujemy się do elementów za pomocą dwóch indeksów: [numer_wiersza, numer_kolumny]. Pamiętaj, że oba indeksy zaczynają się od 0.
Przykład:
using System;
class Program
{
static void Main()
{
// Tablica dwuwymiarowa 3x3 na liczby całkowite
int[,] plansza = new int[3, 3];
// Wypełnianie planszy danymi (ręcznie dla przykładu)
plansza[0, 0] = 1; // Wiersz 0, Kolumna 0
plansza[0, 1] = 2;
plansza[0, 2] = 3;
plansza[1, 0] = 4;
plansza[1, 1] = 5; // Środkowy element
plansza[1, 2] = 6;
plansza[2, 0] = 7;
plansza[2, 1] = 8;
plansza[2, 2] = 9;
// Dostęp do elementu
Console.WriteLine($"Element środkowy: {plansza[1, 1]}"); // Wyświetli 5
// Iterowanie przez tablicę dwuwymiarową (zagnieżdżone pętle for)
Console.WriteLine("\nZawartość planszy:");
for (int wiersz = 0; wiersz < 3; wiersz++) // Pętla dla wierszy
{
for (int kolumna = 0; kolumna < 3; kolumna++) // Pętla dla kolumn
{
Console.Write($"{plansza[wiersz, kolumna]} "); // Wyświetl element
}
Console.WriteLine(); // Po każdym wierszu przejdź do nowej linii
}
}
}
2. Kolekcje (Bardziej elastyczne listy i słowniki)
Tablice są proste, ale mają stały rozmiar. Jeśli chcemy dynamicznie dodawać lub usuwać elementy, potrzebujemy kolekcji. To bardziej zaawansowane struktury danych, które są częścią przestrzeni nazw System.Collections.Generic. Są jak odpowiedniki list i słowników z Pythona.
Aby ich używać, musisz pamiętać o dodaniu using System.Collections.Generic; na początku pliku.
a) List<T> (Dynamiczne listy)
List<T> (gdzie T oznacza dowolny typ danych, np. List<string>, List<int>) to elastyczny odpowiednik tablicy, która może zmieniać swój rozmiar. Jest to najczęściej używana kolekcja w C# i odpowiada listom z Pythona.
Tworzenie listy:
List<typ_elementow> nazwaListy = new List<typ_elementow>();
Przykład: List<string> imiona = new List<string>();
Podstawowe operacje:
Add(element): Dodaje element na koniec listy.Remove(element): Usuwa pierwsze wystąpienie podanego elementu.RemoveAt(index): Usuwa element z podanego indeksu.Insert(index, element): Wstawia element na określoną pozycję.[index]: Dostęp do elementu za pomocą indeksu (jak w tablicy).Count: Właściwość zwracająca aktualną liczbę elementów w liście (odpowiednikLengthdla tablic).Contains(element): Sprawdza, czy lista zawiera dany element (zwracabool).
Przykład:
using System;
using System.Collections.Generic; // WAŻNE! Musisz dodać to 'using'
class Program
{
static void Main()
{
List<string> listaStudentow = new List<string>(); // Pusta lista stringów
Console.WriteLine($"Początkowa liczba studentów: {listaStudentow.Count}"); // 0
listaStudentow.Add("Alicja");
listaStudentow.Add("Bartosz");
listaStudentow.Add("Cezary");
Console.WriteLine($"Po dodaniu: {listaStudentow.Count} studentów"); // 3
Console.WriteLine($"Pierwszy student: {listaStudentow[0]}"); // Alicja
listaStudentow.Remove("Bartosz"); // Usuwamy Bartosza
Console.WriteLine($"Po usunięciu Bartosza: {listaStudentow.Count} studentów"); // 2
listaStudentow.Insert(0, "Dorota"); // Dodajemy Dorotę na początku (indeks 0)
Console.WriteLine($"Po dodaniu Doroty: {listaStudentow[0]}"); // Dorota
// Iterowanie przez listę za pomocą foreach (najczęściej)
Console.WriteLine("\nAktualna lista studentów:");
foreach (string student in listaStudentow)
{
Console.WriteLine($"- {student}");
}
bool czyJestAlicja = listaStudentow.Contains("Alicja");
Console.WriteLine($"\nCzy na liście jest Alicja? {czyJestAlicja}"); // True
}
}
b) Dictionary<TKey, TValue> (Słowniki/Mapy)
Dictionary<TKey, TValue> to kolekcja, która przechowuje dane w parach klucz-wartość (key-value pairs). Każdy klucz (TKey) musi być unikalny, a za jego pomocą możemy szybko odnaleźć odpowiadającą mu wartość (TValue). To bezpośredni odpowiednik słownika z Pythona.
Tworzenie słownika:
Dictionary<typ_klucza, typ_wartosci> nazwaSlownika = new Dictionary<typ_klucza, typ_wartosci>();
Przykład: Dictionary<string, int> wiekUczniow = new Dictionary<string, int>();
Podstawowe operacje:
Add(klucz, wartosc): Dodaje nową parę klucz-wartość.[klucz] = wartosc: Używane do dodawania nowej pary lub modyfikacji istniejącej wartości dla danego klucza.[klucz]: Dostęp do wartości za pomocą klucza.Remove(klucz): Usuwa parę po kluczu.ContainsKey(klucz): Sprawdza, czy słownik zawiera dany klucz (zwracabool).Count: Właściwość zwracająca liczbę par w słowniku.
Przykład:
using System;
using System.Collections.Generic; // WAŻNE! Musisz dodać to 'using'
class Program
{
static void Main()
{
// Słownik przechowujący wiek (int) dla imion (string)
Dictionary<string, int> wiekOsob = new Dictionary<string, int>();
wiekOsob.Add("Jan", 30);
wiekOsob.Add("Anna", 25);
wiekOsob["Piotr"] = 40; // Inny sposób dodawania
Console.WriteLine($"Wiek Anny: {wiekOsob["Anna"]} lat"); // Dostęp do wartości po kluczu
wiekOsob["Jan"] = 31; // Zmiana wieku Jana
Console.WriteLine($"Nowy wiek Jana: {wiekOsob["Jan"]} lat"); // 31
Console.WriteLine($"\nLiczba osób w słowniku: {wiekOsob.Count}"); // 3
if (wiekOsob.ContainsKey("Kasia"))
{
Console.WriteLine("Kasia jest w słowniku.");
}
else
{
Console.WriteLine("Kasia nie jest w słowniku.");
}
// Iterowanie przez słownik (foreach)
Console.WriteLine("\nLista osób i ich wieku:");
foreach (var para in wiekOsob) // 'var' pozwoli C# samodzielnie określić typ (KeyValuePair<string, int>)
{
Console.WriteLine($"- {para.Key}: {para.Value} lat");
}
wiekOsob.Remove("Anna"); // Usuwamy Annę
Console.WriteLine($"\nPo usunięciu Anny, liczba osób: {wiekOsob.Count}"); // 2
}
}
3. Krotki (Tuples)
Krotki w C# to struktury danych, które pozwalają grupować ze sobą wartości o różnych typach. Są lekkie i przydatne, gdy chcemy zwrócić z funkcji kilka wartości naraz, bez tworzenia osobnej klasy. Podobnie jak w Pythonie, wartości w krotce są niezmienne po utworzeniu.
Tworzenie krotki:
(typ1 nazwa1, typ2 nazwa2, ...) nazwaKrotki = (wartosc1, wartosc2, ...);
Możesz też użyć słowa var i pozwolić C# wykryć typy:
var nazwaKrotki = (wartosc1, wartosc2, ...);
Dostęp do elementów krotki: Możesz uzyskać dostęp do elementów krotki za pomocą nadanych im nazw (nazwaKrotki.nazwa1) lub za pomocą domyślnych nazw: Item1, Item2 itd.
Przykład:
using System;
class Program
{
static void Main()
{
// Krotka przechowująca dane o studencie: imię (string), wiek (int), średnia (double)
(string imie, int wiek, double srednia) student = ("Karol", 20, 4.5);
Console.WriteLine($"Student: {student.imie}, wiek: {student.wiek}, średnia: {student.srednia}");
// Można też użyć domyślnych nazw, jeśli nie nadaliśmy własnych
var samochod = ("Toyota", 2020, 15000.0); // Krotka bez nadanych nazw elementów
Console.WriteLine($"Samochód: {samochod.Item1}, rok: {samochod.Item2}, cena: {samochod.Item3}");
// Krotka jako wynik funkcji (później, gdy poznasz funkcje)
var wynikObliczen = ObliczCos(10, 5);
Console.WriteLine($"Suma: {wynikObliczen.suma}, Iloczyn: {wynikObliczen.iloczyn}");
}
// Funkcja zwracająca krotkę
static (int suma, int iloczyn) ObliczCos(int a, int b)
{
return (a + b, a * b);
}
}
Podsumowanie Tablic i Kolekcji:
| Struktura danych | Kiedy używamy? | Kluczowe cechy | Odpowiednik w Pythonie |
| Tablica [] | Stała liczba elementów tego samego typu, znana z góry. | Rozmiar stały, indeksowanie od 0, szybki dostęp do elementu. | (podobne do list, ale o stałym rozmiarze) |
| List<T> | Dynamiczna lista elementów tego samego typu. | Rozmiar zmienny, łatwe dodawanie/usuwanie, indeksowanie od 0. | Lista (list) |
| Dictionary<TKey, TValue> | Dane w parach klucz-wartość. | Klucze unikalne, szybkie wyszukiwanie po kluczu. | Słownik (dict) |
| Krotka () | Grupowanie małej liczby wartości RÓŻNYCH typów. | Niezmienna, lekka, używana do zwracania wielu wartości. | Krotka (tuple) |
Zadania na podsumowanie.
Zadanie 1 – Lista ulubionych filmów Napisz program, który:
- Tworzy listę (
List<string>) o nazwieulubioneFilmy. - Dodaje do niej co najmniej 3 tytuły ulubionych filmów.
- Wyświetla wszystkie filmy z listy, używając pętli
foreach. - Pyta użytkownika, czy chce usunąć jakiś film z listy (po nazwie). Jeśli film istnieje, usuń go i wyświetl nową listę. Jeśli nie, wyświetl komunikat, że filmu nie ma.
- Na koniec wyświetl, ile filmów pozostało na liście.
Zadanie 2 – Dane kontaktowe (Słownik) Napisz program, który:
- Tworzy słownik (
Dictionary<string, string>) o nazwiekontakty, gdzie kluczem będzie imię, a wartością numer telefonu. - Dodaje do słownika co najmniej 3 przykładowe kontakty (imię i numer).
- Pyta użytkownika o imię osoby, której numer telefonu chce sprawdzić.
- Jeśli imię istnieje w słowniku, wyświetl numer telefonu tej osoby.
- Jeśli imienia nie ma w słowniku, wyświetl komunikat „Brak kontaktu dla tej osoby.”
Zadanie 3 – Dane osoby (Krotka) Napisz program, który:
- Definiuje krotkę o nazwie
osobazawierającą:stringimię,stringnazwisko,intwiek.
- Przypisz do tej krotki dane jakiejś osoby (np. Twoje).
- Wyświetl dane osoby z krotki w czytelnym formacie, np. „Imię: [imię], Nazwisko: [nazwisko], Wiek: [wiek]”.
Lekcja 9. Praca z Plikami (Odczyt i Zapis danych)
Do tej pory nasze programy działały „na żywo”: dane, które podał użytkownik, były używane, a po zakończeniu programu… znikały. Jeśli chcielibyśmy, żeby program pamiętał coś na przyszłość – np. listę zakupów, wysoki wynik w grze, czy ustawienia – musimy zapisać te dane do pliku.
Praca z plikami pozwala naszym programom komunikować się ze światem zewnętrznym i przechowywać informacje na stałe na dysku komputera.
Co to jest plik?
Wyobraź sobie plik jako zeszyt lub segregator na komputerze. Możesz w nim zapisywać informacje (tekst, liczby, obrazy – cokolwiek) i odczytywać je później. Każdy plik ma swoją nazwę i lokalizację na dysku.
W C# (i w ogóle w programowaniu) najczęściej pracujemy z plikami tekstowymi. Poznaliśmy już podstawowy format TXT, ale istnieje też inny, niezwykle popularny format: JSON.
Przestrzeń nazw System.IO
Aby móc pracować z plikami w C#, musimy dodać na początku naszego pliku instrukcję using:
using System.IO; // Ta przestrzeń nazw zawiera narzędzia do pracy z plikami i folderami
Ta linijka daje nam dostęp do klas takich jak File, StreamReader, StreamWriter, które służą do operacji na plikach.
1. Zapisywanie danych do pliku TXT (Pisanie)
Najprostszym sposobem na zapisywanie tekstu do pliku jest użycie klasy File i jej metody WriteAllText().
Schemat działania:
File.WriteAllText("sciezka/do/pliku.txt", "Tekst, który chcemy zapisać.");
File.WriteAllText(): Ta metoda statyczna z klasyFilesłuży do zapisania całego podanego tekstu do pliku.- Pierwszy argument: Ścieżka do pliku (nazwa pliku). Jeśli podasz tylko nazwę pliku (
"mojplik.txt"), zostanie on utworzony w tym samym katalogu, co uruchomiony program. Możesz też podać pełną ścieżkę ("C:/MojeDokumenty/dane.txt"). - Drugi argument: Tekst, który ma zostać zapisany do pliku.
- Pierwszy argument: Ścieżka do pliku (nazwa pliku). Jeśli podasz tylko nazwę pliku (
Ważne: Jeśli plik o podanej nazwie już istnieje, metoda WriteAllText() nadpisze (skasuje i zastąpi) jego zawartość nowym tekstem!
Przykład: Zapisywanie prostego tekstu
using System;
using System.IO; // Pamiętaj o tej linijce!
class Program
{
static void Main()
{
string nazwaPlikuTxt = "moja_wiadomosc.txt";
string tekstDoZapisu = "Witaj, świecie plikowy!\nTo jest kolejna linia tekstu.";
try // Zawsze warto używać try-catch przy operacjach na plikach!
{
File.WriteAllText(nazwaPlikuTxt, tekstDoZapisu);
Console.WriteLine($"Tekst został zapisany do pliku: {nazwaPlikuTxt}");
}
catch (Exception ex) // Obsługa błędów, np. brak dostępu do pliku
{
Console.WriteLine($"Wystąpił błąd podczas zapisu: {ex.Message}");
}
}
}
Po uruchomieniu tego kodu, w katalogu obok pliku .exe twojego programu pojawi się plik moja_wiadomosc.txt z zapisanym tekstem.
2. Odczytywanie danych z pliku TXT (Czytanie)
Aby odczytać całą zawartość pliku tekstowego, również możemy użyć klasy File, a konkretnie metody ReadAllText().
Schemat działania:
string zawartosc = File.ReadAllText("sciezka/do/pliku.txt");
File.ReadAllText(): Ta metoda statyczna odczytuje całą zawartość pliku i zwraca ją jako jeden długistring.- Argument: Ścieżka do pliku, który chcemy odczytać.
Ważne: Jeśli plik o podanej nazwie nie istnieje, program zgłosi błąd (FileNotFoundException)!
Przykład: Odczytywanie zapisanego tekstu
using System;
using System.IO; // Pamiętaj o tej linijce!
class Program
{
static void Main()
{
string nazwaPlikuTxt = "moja_wiadomosc.txt"; // Plik, który zapisaliśmy wcześniej
try
{
string odczytanyTekst = File.ReadAllText(nazwaPlikuTxt);
Console.WriteLine($"\n--- Zawartość pliku {nazwaPlikuTxt} ---");
Console.WriteLine(odczytanyTekst);
Console.WriteLine("---------------------------------\n");
}
catch (FileNotFoundException) // Konkretny błąd, gdy plik nie istnieje
{
Console.WriteLine($"Błąd: Plik '{nazwaPlikuTxt}' nie został znaleziony.");
}
catch (Exception ex) // Inne błędy
{
Console.WriteLine($"Wystąpił błąd podczas odczytu: {ex.Message}");
}
}
}
Wskazówka: Dobrą praktyką jest umieszczanie operacji na plikach w bloku try-catch, aby bezpiecznie obsłużyć ewentualne błędy, takie jak brak pliku, brak uprawnień do zapisu/odczytu itp.
3. Dopisanie danych do pliku TXT (Dodawanie)
Co, jeśli chcemy dodać nowy tekst na koniec istniejącego pliku, zamiast nadpisywać całą jego zawartość? Używamy metody AppendAllText().
Schemat działania:
File.AppendAllText("sciezka/do/pliku.txt", "Tekst do dopisania.");
File.AppendAllText(): Dopisuje podany tekst na koniec pliku.- Jeśli plik nie istnieje, zostanie utworzony.
- Jeśli plik istnieje, tekst zostanie dodany na jego końcu.
Przykład: Dopisanie nowej linii do pliku logu
using System;
using System.IO;
class Program
{
static void Main()
{
string plikLogu = "log.txt";
string nowaWiadomosc = $"{DateTime.Now}: Program uruchomiony ponownie.\n"; // Dodajemy datę i czas
try
{
File.AppendAllText(plikLogu, nowaWiadomosc);
Console.WriteLine($"Wiadomość została dopisana do pliku: {plikLogu}");
// Możemy od razu sprawdzić zawartość
Console.WriteLine("\n--- Aktualna zawartość log.txt ---");
Console.WriteLine(File.ReadAllText(plikLogu));
}
catch (Exception ex)
{
Console.WriteLine($"Wystąpił błąd: {ex.Message}");
}
}
}
4. Praca z plikami TXT linia po linii (Listy tekstów)
Często wygodniej jest odczytywać lub zapisywać pliki tekstowe jako listę linii, a nie jeden długi string.
File.ReadAllLines("sciezka.txt"): Odczytuje wszystkie linie z pliku i zwraca je jako tablicę typustring[], gdzie każdy element tablicy to jedna linia z pliku.File.WriteAllLines("sciezka.txt", string[] linie): Zapisuje każdą linię z podanej tablicystringdo pliku.
Przykład: Lista zadań do zrobienia
using System;
using System.IO;
using System.Collections.Generic; // Potrzebne do List<string>
class Program
{
static void Main()
{
string plikZadan = "zadania.txt";
// ---------------- ZAPISYWANIE ZADAŃ ----------------
List<string> listaZadan = new List<string>
{
"Kupić mleko",
"Zadzwonić do babci",
"Napisać kod C#",
"Poczytać książkę"
};
try
{
// Konwertujemy List<string> na string[] dla WriteAllLines
File.WriteAllLines(plikZadan, listaZadan.ToArray());
Console.WriteLine($"Zadania zapisane do pliku: {plikZadan}");
}
catch (Exception ex)
{
Console.WriteLine($"Błąd podczas zapisu zadań: {ex.Message}");
}
// ---------------- ODCZYTYWANIE ZADAŃ ----------------
try
{
Console.WriteLine($"\n--- Twoje zadania z pliku {plikZadan} ---");
string[] odczytaneZadania = File.ReadAllLines(plikZadan); // Odczytujemy jako tablicę linii
foreach (string zadanie in odczytaneZadania)
{
Console.WriteLine($"- {zadanie}");
}
}
catch (FileNotFoundException)
{
Console.WriteLine($"Błąd: Plik zadań '{plikZadan}' nie został znaleziony.");
}
catch (Exception ex)
{
Console.WriteLine($"Błąd podczas odczytu zadań: {ex.Message}");
}
}
}
5. Praca z plikami JSON (Dane strukturalne)
Pliki JSON (JavaScript Object Notation) to tekstowy format wymiany danych, bardzo popularny w webowych aplikacjach i wszędzie tam, gdzie trzeba przesyłać lub przechowywać dane w ustrukturyzowany sposób. Zamiast prostego tekstu, JSON pozwala na reprezentowanie obiektów (jak słowniki) i list (jak tablice).
Dlaczego JSON jest popularny?
- Łatwy do czytania dla ludzi.
- Łatwy do parsowania (przetwarzania) przez maszyny.
- Powszechnie używany w internecie (API).
Podstawowe typy danych w JSON:
- Obiekt (odpowiednik słownika/obiektu w C#):
{ "klucz": "wartość", "innyKlucz": 123 } - Tablica (odpowiednik listy/tablicy w C#):
[ "element1", "element2", 3 ] - Wartości: stringi (w cudzysłowach), liczby, booleany (
true/false),null.
Obsługa JSON w C# (System.Text.Json)
Aby pracować z JSON w C#, będziemy potrzebować biblioteki System.Text.Json. Jest ona częścią .NET (od .NET Core 3.0 i .NET 5+), więc nie musisz instalować nic dodatkowego, wystarczy dodać using:
using System.Text.Json; // Ważne!
Kluczowe operacje:
- Serializacja: Zamiana obiektu C# na tekst JSON (zapis do pliku).
- Deserializacja: Zamiana tekstu JSON na obiekt C# (odczyt z pliku).
Aby to zademonstrować, stwórzmy prostą klasę C#, która będzie odpowiadała strukturze danych w JSON.
// Ta klasa reprezentuje "osobę"
public class Osoba
{
public string Imie { get; set; } // Właściwość na imię
public int Wiek { get; set; } // Właściwość na wiek
public bool JestStudentem { get; set; } // Właściwość na status studenta
}
a) Zapisywanie obiektu do pliku JSON (Serializacja)
using System;
using System.IO;
using System.Text.Json; // Dodaj to using!
class Program
{
static void Main()
{
// 1. Tworzymy obiekt C#
Osoba nowaOsoba = new Osoba
{
Imie = "Anna Kowalska",
Wiek = 28,
JestStudentem = false
};
// 2. Konwertujemy obiekt C# na tekst JSON (serializacja)
// Opcja 'WriteIndented = true' sprawia, że JSON jest ładnie sformatowany (z wcięciami)
var options = new JsonSerializerOptions { WriteIndented = true };
string jsonString = JsonSerializer.Serialize(nowaOsoba, options);
// 3. Zapisujemy tekst JSON do pliku
string nazwaPlikuJson = "osoba.json";
try
{
File.WriteAllText(nazwaPlikuJson, jsonString);
Console.WriteLine($"Obiekt zapisano do pliku: {nazwaPlikuJson}");
}
catch (Exception ex)
{
Console.WriteLine($"Błąd podczas zapisu JSON: {ex.Message}");
}
}
}
// Musisz zdefiniować tę klasę gdzieś w swoim pliku (np. na samym dole)
public class Osoba
{
public string Imie { get; set; }
public int Wiek { get; set; }
public bool JestStudentem { get; set; }
}
Po uruchomieniu tego kodu, w pliku osoba.json zobaczysz coś takiego:
JSON
{
"Imie": "Anna Kowalska",
"Wiek": 28,
"JestStudentem": false
}
b) Odczytywanie obiektu z pliku JSON (Deserializacja)
C#
using System;
using System.IO;
using System.Text.Json; // Dodaj to using!
class Program
{
static void Main()
{
string nazwaPlikuJson = "osoba.json"; // Plik, który zapisaliśmy wcześniej
try
{
// 1. Odczytujemy cały tekst z pliku JSON
string jsonString = File.ReadAllText(nazwaPlikuJson);
// 2. Konwertujemy tekst JSON na obiekt C# (deserializacja)
Osoba odczytanaOsoba = JsonSerializer.Deserialize<Osoba>(jsonString);
// 3. Używamy danych z obiektu C#
Console.WriteLine($"\n--- Dane odczytane z pliku {nazwaPlikuJson} ---");
Console.WriteLine($"Imię: {odczytanaOsoba.Imie}");
Console.WriteLine($"Wiek: {odczytanaOsoba.Wiek}");
Console.WriteLine($"Student: {odczytanaOsoba.JestStudentem}");
}
catch (FileNotFoundException)
{
Console.WriteLine($"Błąd: Plik '{nazwaPlikuJson}' nie został znaleziony.");
}
catch (Exception ex)
{
Console.WriteLine($"Wystąpił błąd podczas odczytu/deserializacji JSON: {ex.Message}");
}
}
}
// Ta klasa musi być zdefiniowana, aby działała deserializacja!
public class Osoba
{
public string Imie { get; set; }
public int Wiek { get; set; }
public bool JestStudentem { get; set; }
}
Podsumowanie Pracy z Plikami:
| Format pliku | Kiedy używamy? | Metody / Biblioteki |
| TXT | Prosty, nieskomplikowany tekst; logi; proste listy. | System.IO.File.WriteAllText/ReadAllText System.IO.File.AppendAllText/ReadAllLines |
| JSON | Dane strukturalne (obiekty, listy obiektów); konfiguracje; wymiana danych z API. | System.Text.Json.JsonSerializer.Serialize/Deserialize |
Zadania na podsumowanie.
Zadanie 1 – Dziennik pogody (rozszerzony) Napisz program, który:
- Poprosi użytkownika o podanie aktualnej temperatury (np.
22.5). - Poprosi o krótki opis pogody (np. „Słonecznie”).
- Zapisze te dane do pliku o nazwie
pogoda.txt. Każdy wpis powinien być w nowej linii i zawierać datę i czas, temperaturę i opis.- Wskazówka: Użyj
DateTime.Now.ToString()dla daty i czasu, a do zapisuFile.AppendAllText(), aby kolejne wpisy były dopisywane, a nie nadpisywane. - Format linii:
[Data i Czas] Temperatura: [temperatura]°C, Opis: [opis]
- Wskazówka: Użyj
Zadanie 2 – Lista ulubionych dań (JSON) Napisz program, który:
- Zdefiniuje prostą klasę np.
public class Danie { public string Nazwa { get; set; } public int Kalorie { get; set; } }. - Stworzy listę obiektów
List<Danie>(np. dwa-trzy dania z nazwami i kaloriami). - Zapisze (serializuje) tę listę do pliku JSON o nazwie
ulubione_dania.json. - Następnie odczyta (deserializuje) tę listę z pliku JSON.
- Wyświetli na konsoli nazwy i kalorie wszystkich odczytanych dań.
Przykład pliku JSON, który powinien powstać:
[
{
"Nazwa": "Pizza",
"Kalorie": 800
},
{
"Nazwa": "Sałatka Cezar",
"Kalorie": 450
}
]
- Wskazówka: Do serializacji/deserializacji listy użyj:
string jsonString = JsonSerializer.Serialize(listaDan, options);List<Danie> odczytaneDania = JsonSerializer.Deserialize<List<Danie>>(jsonString);
Zadanie 3 – Ustawienia programu (JSON) Napisz program, który:
- Zdefiniuje klasę
public class Ustawienia { public string NazwaUzytkownika { get; set; } public bool TrybCiemny { get; set; } }. - Stworzy obiekt
Ustawieniaz przykładowymi danymi. - Zapisze ten obiekt do pliku
ustawienia.json. - Odczyta obiekt
Ustawieniaz pliku. - Wyświetli odczytane ustawienia na konsoli.
