WarunkiCzęść NR.5Programy służą do rozwiązywania złożonych problemów. W tym celu program nie może działać liniowo. Niczym gra Visual Novel, w której w zależności od podjętej przez nas decyzji na ekranie komputera oglądamy inny tekst.

Myślę ,że jest to najlepszy przykład. W takiej grze istnieją proste zmienne bądź liczniki punktów, które decydują o tym, co później się wydarzy.

Potem za pomocą twierdzeń decyzyjnych zawartych w programie zmienne przekierowują nas do odpowiednich scen w grze.

Na tym przykładzie przedstawionym na ilustracji postać w garniturze o imieniu “Enomoto” pyta, czy słyszałem o kwantowej teleportacji? . Jeśli odpowiem “tak” to zostanie pominięta cała scena (jak nie rozdział) tłumacząca co to jest kwantowa teleportacja.
Twierdzenia decyzjne
Mam nadzieje ,że przykład spodobał się . Każdy program działa w zależności od decyzji użytkownika. Nasz poprzedni przykład aplikacji WPF obliczał wynik w zależności od wciśniętego przycisku ,ale ile musielibyśmy mieć przycisków do każdej operacji matematycznej. Tymczasem każdy wie ,że w kalkulatorze jest jeden przycisk “równa się", który wszystko zatwierdza .

Jednym słowem by nie powielać kodu musimy po prostu poinformować program ,że w danym przypadku musi wykonać inną operację.

To byłoby tyle, jeśli chodzi o wstęp. Teraz pokażę jak można osiągnąć to w kodzie w C#.

Wartości logiczne

W C# zmienna typu bool może przechowywać tylko dwa stany: prawda bądź fałsz (true or false).

Wartości logiczne występują też przy porównaniach. Jeśli zadeklarowałeś zmienną X i przypisałeś do niej wartość 5, po czym spytałeś “czy ta dana ma wartość 5” to otrzymasz wartość: true. .

Jak pamiętasz z części drugiej tego kursu kompilator nie pozwoli na kompilację programu z porównaniem zmiennych, gdzie chociaż jedna z nich jest zmienną nieprzypisaną. Czyli by porównywać zmienne muszą one zawierać w sobie jakąś wartość.W innych językach jak C i C++ jest to możliwe. Co powoduje wiele głupich błędów.

W C# istnieje też typ bool?, który może też przechowywać stan pusty, ale nie będziemy sobie zawracać nim głowy.

Przykład zastosowania zmiennej typu bool.

bool zrobione;
zrobione = true;
Console.WriteLine(zrobione);

Porównywanie wartości

Do porównywania wartości w C# używa się dwóch znaków równa się “==” , a do sprawdzenia ich nierówności wykrzyknika i znaku równa się “!=”.

Nie myl znaku przypisywania (“=”) z porównywaniem wartości (“==”), która zawsze zwraca wartość logiczną bool. Rozumiem ,że intuicyjne porównanie wartości z matematycznego punktu widzenia może się kojarzyć z jednym znakiem równa się.

Oczywiście możemy porównywać tylko zmienne, które są tego samego typu jak np. int.

OperatorZnaczeniePrzykładWynik, jeśli liczba=20
==Równa sięliczba == 20true
!=Nie równa sięliczba =! 0true


Przykład kodu:

int a = 5;
int b = 2;
bool rownasie = a == b;
Console.WriteLine(rownasie);//false 
Console.WriteLine(a != b);//true 

Tak jak w matematyce dla wartości liczbowych możemy sprawdzić, czy dana zmienna zawiera się w danym przedziale liczbowym.

OperatorZnaczeniePrzykładWynik, jeśli liczba=20
<Mniejsze niżliczba < 20false
<=Mniejsze bądź równeliczba <= 20true
>Większe niżliczba > 30false
>=Większe bądź równeliczba >=16true


Przykład kodu:

int liczba = 20;
Console.WriteLine(liczba < 18);//false
Console.WriteLine(liczba <= 20);//true
Console.WriteLine(liczba > 30);//false 
Console.WriteLine(liczba >= 16);//true

Operacje logiczne

Operacje logiczne to jedno z zagadnień w matematyce znajomość, których bardzo się przydaje . Operator logiczny przekształca daną wartość logiczną na prawdę albo fałsz. Przykładowo “negacja” przekształca wartość logiczną na jej odwrotność. Ten operator logiczny jest wyrażony za pomocą wykrzyknika “!”.

Czyli operacja “!zrobione” zwróci wartość true ,jeśli przechowywała wartość false.

bool zrobione = false;
Console.WriteLine(!zrobione);//true 
Console.WriteLine(!true);//false 

W C# mamy też do dyspozycji operatory logiczne jak AND reprezentowane przez symbol && jak i OR reprezentowany przez symbol || .

Celem ich jest otrzymanie określonej wartości logicznej poprzez odpowiednią kombinacje dwóch wartości logicznych.

Oto krótkie przypomnienie tych operacji binarnych. Gdzie “1” reprezentuje prawdę ,a “0” fałsz.

X1X2 ANDOR
00 00
01 01
10 01
11 11


Czyli wynik operacji AND, czyli symbolu “&&” jest prawdziwy tylko wtedy, gdy dwa wyrażenia logiczna też są prawdziwe. Dla wyrażenia OR, czyli symbolu “||” tylko wtedy, gdy oba wyrażenia logiczne są fałszywe, otrzymujesz fałsz.

Zastosowanie w kodzie tych wyrażeń wygląda następująco.

bool WyjscNaSpacer;
int temperatura = 20;
WyjscNaSpacer = (temperatura >= 10) && (temperatura <= 30);

Zwróć uwagę na zastosowanie nawiasów.

Podane wyrażenie sprawdza czy mam wyjść na spacer. Jeśli temperatura jest większa bądź równa 10 oraz temperatura jest mniejsza, bądź równa 30 to wyjdę na zewnątrz .To wyrażenie zwróci prawdę, ponieważ temperatura równa się 20 i zawiera się w tym zbiorze.

O to przykład operacji OR.

bool ZostacWDomu;
int temperatura = 5;
ZostacWDomu = (temperatura < 10) || (temperatura > 30);

Jeśli temperatura jest mniejsza od 10 albo większa od 30 to zostanę w domu ,ponieważ temperatura równa się 5 to warunki do zastania w domu zostały spełnione, zatem to twierdzenie zwróci prawdę.

Pamiętaj by dobrze rozplanować wyrażenia logiczne. W matematyce mamy do dyspozycji Algebre Boola’e by skracać wyrażenia logiczne do najprostszej postaci. Dwa poprzednie przykłady wykazały ,że można podejść na dwa sposoby do określonego problemu, jak “wyjście na spacer przy określonej temperaturze” z zastosowaniem AND i OR.

W programowaniu rzadko zdarzają się skomplikowane wyrażenia logiczne ,ale miej to na uwadze.

Używanie wyrażenia “if”

OK, teraz masz ogólny pogląd jak wyrażenia logiczne działają w C# ale myślę ,że najwyższy czas pokazać co można za pomocą wyrażeń logicznych zrobić w C#.

Gdy chcemy wybrać dwa różne bloki kodu w zależności od danej wartości bądź od danego wyrażenia logicznego stosujemy słowo kluczowe if i else.

int a = 0;
if (a == 0)
{
    //kod 
}

W if blok kodu wykona się, jeśli wyrażenie logiczne w nim zawarte zwraca wartość true. Jeśli do kodu pod wyrażeniem if napisaliśmy słowo kluczowe “else” to w wypadku niespełnienia się warunku if wykona się ten fragment kodu.

Wracając do przykładu ze wstępu. Przykładowe zastosowanie “if” i “else” wygląda tak. Za pomocą zdarzenia “ReadLine()” z klasy “Console” pobieram linijkę napisaną przez użytkownika. Jeśli linijka ta równa się “nie” bądź “Nie” wtedy w konsoli wyświetli się opis kwantowej teleportacji. W przeciwnym wypadku zostanie wyświetlony inny komunikat.

string TwojeZdanie = Console.ReadLine();
Console.ForegroundColor = ConsoleColor.DarkYellow;
if ((TwojeZdanie == "nie") || (TwojeZdanie == "Nie"))
{
    Console.WriteLine("Rozumiem w takim razie musze zacząć od tego.");
    Console.WriteLine("Kwantowa teleportacja to technika bazująca na właściwościach kwantowej mechaniki");
    Console.WriteLine("Teleportacja-to zdolność do natychmiastowego transportu obiektu do...");
    Console.WriteLine("Nie 'transport obiektu' nie jest dobrym wyrażeniem");
    Console.WriteLine("Będąc bardziej dokładnym...nie transportujemy obiektu tylko...");
    Console.WriteLine("...jego informacje");
    Console.WriteLine("Bla bla");
}
else {
    Console.WriteLine("\t To bardzo dobrze. ");
    Console.WriteLine("\t To skróci tą część tłumaczenia jak to urządzenie działa");

}
Console.WriteLine("");
Console.WriteLine("Teraz gdy wiesz czym jest kwantowa teleportacja..");

Pod koniec wyrażenia if i else wyświetla się komunikat, który nie jest zależy od podjętej przez nas decyzji.

image

 
Wyrażenie if zostało spełnione
 
 
 
image_1
 
 
 
Wyrażenie if nie zostało spełnione wykonał się blok kodu z else


Przy stosowaniu wyrażeniu if pamiętaj ,że on sprawdza czy wyrażenie jest poprawne. Czyli pisanie takiego kodu if jest ok ,ale zmusza on program do wykonania jednej niepotrzebnej operacji.

bool cos = true;
if (cos) // lepszy styl 
if (cos == true) //gorszy styl 


cast bool to bool

Z drugiej strony przy aplikacjach WPF czasami pojawiają się wartość logiczne z 3 wartością pustą i wtedy wykonanie dodatkowej operacji ma sens, ponieważ if nie obsługuje automatycznie wyrażenia logicznego z trzema wartościami.

Blok kodu

Jak zauważyłeś w poprzednim przykładzie blok kodu z wyrażenia kluczowego if i else jest zawarty w nawiasach { }. Warto tutaj zaznaczyć jak zachowują się zmienne utworzone w tych blokach kodu. Zapewne jak się domyślasz zmienne utworzone w tym blokach są dostępne tylko w nich.

blok kodu i zmienne
Zmienne zdefiniowane w środku takiego bloku znikają po jego zakończeniu. Do poprawnego użycia tego kodu zmienna musi być zadeklarowana przed jego blokiem ,oczywiście dla bezpieczeństwa, ponieważ nie mamy pewności czy dany kod w if wykona się więc musimy dać mu wartość domyślną.

bool cos = true;
int zmienna =0;

if (cos)
{
   zmienna = 12;
}

Console.WriteLine(zmienna);

Stosowanie nawiasów klamrowych nie jest koniecznie, jeśli nasz kod warunkowy zawiera się tylko w jednej linijce. Chociaż dzięki nawiasom klamrowym wiemy, która część kodu przynależy do odpowiedniego warunku.

bool cos = true;
int zmienna =0;

if (cos)
   zmienna = 12;
else    zmienna = 6;

Console.WriteLine(zmienna);

Kaskadowe wyrażenie if

Nic nie stoi na przeszkodzie by pisać wyrażenia if , które będą działać łańcuchowo. Do tego mamy słowo kluczowe else if.

Przykład pokazuje komunikat, który ma się wyświetlić w zależności od wielkość zmiennej CzasSnu.

int CzasSnu;
CzasSnu = 8;
if (CzasSnu  <= 3)
    Console.WriteLine("To była mała drzemka.Musze więcej spać.");
else if (CzasSnu <= 5)
    Console.WriteLine("Czuje się wciąż zmęczony");
else if (CzasSnu <= 7)
    Console.WriteLine("To był dobry sen.Ale mam mały ból głowy.");
else if (CzasSnu <= 9)
    Console.WriteLine("Czuje się silniejszy");
else if (CzasSnu <= 12) 
    Console.WriteLine("Za długo spałem");
else Console.WriteLine("Nie zrozumiała komenda");

Najpierw sprawdzany będzie pierwszy zapis if .Gdy on będzie fałszywy będzie wykonywał się cały łańcuch wyrażeń else if w kolejność w jakiej zostały podane. Gdy żaden else if nie będzie prawdziwy wykona się zapis else.

Jest to na pewno efektywniejszy zapis niż ten.

int CzasSnu;
CzasSnu = 4;
if (CzasSnu <= 3)
{}

if ((CzasSnu <= 5) && (CzasSnu > 3))
{ }

Ponieważ po każdy kolejnym else if wiemy ,że wartość nie spełniła poprzedniego warunku.

Switch

Czasami, kiedy mamy warunki jedne po drugim warto jest zastanowić się, czy nie lepiej je przepisać na wyrażenie Switch. Akurat poprzedni przykład do tego nie nadawałby się ze względu na wyrażenia mniejsze bądź równe.

string PolskaLiczba = "jeden";
if (PolskaLiczba == "jeden")
    Console.WriteLine(1);
else if (PolskaLiczba == "dwa")
    Console.WriteLine(2);
else if (PolskaLiczba == "trzy")
    Console.WriteLine(3);
else Console.WriteLine("Nie znane");

Ale gdybyśmy mieli do dyspozycje takie wyrażenie kaskadowe if to napisanie jego w stylu switch/case byłoby opłacalne i bardziej czytelne dla programisty.

Wyrażenie switch,które robi dokładnie to samo co poprzedni przykład else if jest następujące:

string PolskaLiczba = "jeden";
switch (PolskaLiczba)
{
    case "jeden":
        Console.WriteLine(1);
        break;
    case "dwa":
        Console.WriteLine(2);
        break;
    case "trzy" Console.WriteLine(3);
        break;
    default:
        Console.WriteLine("Nie znane");
        break;
}

Zasady zastosowania switch są następujące:

  • Możesz przełączać się tylko pomiędzy typami jak int i string. Typy takie jak double i float nie są akceptowane.
  • Nie mogą występować dwa takie same przypadki “case” z tą samą wartością
  • Wartość zadeklarowana w case muszą być stała. Nie można w case wykonywać operacji arytmetycznych
  • Nie możesz określić tego samego bloku kodu dla różnych wartości jak w if. Coś takiego nie może wystąpić:
case "jeden","cztery":
Console.WriteLine(1);
break;

Słowo kluczowe break informuje kompilator ,że wyrażenie switch wykonało swoją operację. Więcej informacji o tym słowie kluczowym w następnym wpisie.

To by było na tyle:

W następnym odcinku pętle i inne iteracje.