Wprowadzenie do operatorów
Operatory to specjalne symbole lub słowa kluczowe, które wykonują określone operacje na zmiennych, stałych lub wyrażeniach. W C# operatory pozwalają nam:
- Wykonywać obliczenia matematyczne
- Porównywać wartości
- Łączyć warunki logiczne
- Przypisywać wartości do zmiennych
- Manipulować bitami i wykonywać inne zaawansowane operacje
Składniki operacji
- Operand – wartość, na której wykonywana jest operacja
- Operator – symbol określający rodzaj operacji
- Wynik – rezultat operacji
int a = 5; // a i 5 to operandy, = to operator przypisania
int b = 3; // b i 3 to operandy, = to operator przypisania
int wynik = a + b; // a, b to operandy, + to operator dodawania, wynik = 8Kategorie operatorów
W C# operatory dzielimy na kilka głównych kategorii:
- Operatory arytmetyczne – obliczenia matematyczne
- Operatory przypisania – przypisywanie wartości
- Operatory porównania (relacyjne) – porównywanie wartości
- Operatory logiczne – operacje na wartościach logicznych
- Operatory bitowe – operacje na bitach
- Operatory warunkowe – decyzje i wybory
- Operatory typu – sprawdzanie i konwersja typów
- Inne operatory – specjalne przypadki
1. Operatory arytmetyczne
Służą do wykonywania podstawowych operacji matematycznych.
Podstawowe operatory arytmetyczne:
| Operator | Nazwa | Opis | Przykład |
|---|---|---|---|
+ | Dodawanie | Dodaje dwa operandy | 5 + 3 = 8 |
- | Odejmowanie | Odejmuje drugi operand od pierwszego | 5 - 3 = 2 |
* | Mnożenie | Mnoży dwa operandy | 5 * 3 = 15 |
/ | Dzielenie | Dzieli pierwszy operand przez drugi | 6 / 3 = 2 |
% | Modulo (reszta z dzielenia) | Zwraca resztę z dzielenia | 7 % 3 = 1 |
Przykłady praktyczne:
// Podstawowe operacje
int a = 15;
int b = 4;
int suma = a + b; // 19
int roznica = a - b; // 11
int iloczyn = a * b; // 60
int iloraz = a / b; // 3 (dzielenie całkowite!)
int reszta = a % b; // 3 (15 = 3*4 + 3)
Console.WriteLine($"{a} + {b} = {suma}");
Console.WriteLine($"{a} - {b} = {roznica}");
Console.WriteLine($"{a} * {b} = {iloczyn}");
Console.WriteLine($"{a} / {b} = {iloraz}");
Console.WriteLine($"{a} % {b} = {reszta}");Dzielenie całkowite vs zmiennoprzecinkowe:
// Dzielenie całkowite
int x = 7;
int y = 2;
int wynikInt = x / y; // 3 (część dziesiętna odrzucona)
int resztaInt = x % y; // 1
// Dzielenie zmiennoprzecinkowe
double wynikDouble = (double)x / y; // 3.5 (rzutowanie na double)
double wynikDouble2 = 7.0 / 2.0; // 3.5 (literały double)
Console.WriteLine($"Dzielenie całkowite: {x}/{y} = {wynikInt}, reszta = {resztaInt}");
Console.WriteLine($"Dzielenie rzeczywiste: {wynikDouble}");Operatory unarne (jeden operand):
int liczba = 5;
int dodatnia = +liczba; // +5 (operator plus unarny)
int ujemna = -liczba; // -5 (operator minus unarny)
int zwiększona = ++liczba; // 6 (pre-increment)
int zmniejszona = --liczba; // 5 (pre-decrement)
Console.WriteLine($"Oryginalna: {5}");
Console.WriteLine($"Dodatnia: {dodatnia}");
Console.WriteLine($"Ujemna: {ujemna}");Increment i decrement – różnice:
int a = 5;
int b = 5;
// Pre-increment/decrement - najpierw zmiana, potem użycie
int wynik1 = ++a; // a = 6, wynik1 = 6
int wynik2 = --b; // b = 4, wynik2 = 4
Console.WriteLine($"Pre-increment: a={a}, wynik1={wynik1}");
Console.WriteLine($"Pre-decrement: b={b}, wynik2={wynik2}");
// Post-increment/decrement - najpierw użycie, potem zmiana
int c = 5;
int d = 5;
int wynik3 = c++; // wynik3 = 5, potem c = 6
int wynik4 = d--; // wynik4 = 5, potem d = 4
Console.WriteLine($"Post-increment: c={c}, wynik3={wynik3}");
Console.WriteLine($"Post-decrement: d={d}, wynik4={wynik4}");Operatory arytmetyczne z innymi typami:
// String concatenation
string imie = "Jan";
string nazwisko = "Kowalski";
string pełneImie = imie + " " + nazwisko; // "Jan Kowalski"
// Mieszanie typów
int liczbaInt = 10;
double liczbaDouble = 3.5;
double wynik = liczbaInt + liczbaDouble; // 13.5 (int → double)
// Char jako liczby
char litera = 'A';
int kodASCII = litera + 0; // 65
char nastepnaLitera = (char)(litera + 1); // 'B'
Console.WriteLine($"Kod ASCII 'A': {kodASCII}");
Console.WriteLine($"Następna litera: {nastepnaLitera}");2. Operatory przypisania
Służą do przypisywania wartości do zmiennych.
Podstawowy operator przypisania:
int x; // deklaracja
x = 10; // przypisanie wartości 10 do x
int y = 20; // deklaracja z jednoczesnym przypisaniemZłożone operatory przypisania:
| Operator | Długa forma | Krótka forma | Opis |
|---|---|---|---|
+= | x = x + y | x += y | Dodaje i przypisuje |
-= | x = x - y | x -= y | Odejmuje i przypisuje |
*= | x = x * y | x *= y | Mnoży i przypisuje |
/= | x = x / y | x /= y | Dzieli i przypisuje |
%= | x = x % y | x %= y | Modulo i przypisuje |
int liczba = 10;
liczba += 5; // liczba = liczba + 5 → 15
liczba -= 3; // liczba = liczba - 3 → 12
liczba *= 2; // liczba = liczba * 2 → 24
liczba /= 4; // liczba = liczba / 4 → 6
liczba %= 4; // liczba = liczba % 4 → 2
Console.WriteLine($"Końcowy wynik: {liczba}");
// Przykłady z innymi typami
string tekst = "Hello";
tekst += " World"; // "Hello World"
double saldo = 1000.0;
saldo *= 1.05; // Podwyżka o 5% → 1050.03. Operatory porównania (relacyjne)
Porównują dwie wartości i zwracają wynik typu bool (true lub false).
Tabela operatorów porównania:
| Operator | Nazwa | Opis | Przykład |
|---|---|---|---|
== | Równość | Sprawdza czy operandy są równe | 5 == 5 → true |
!= | Nierówność | Sprawdza czy operandy są różne | 5 != 3 → true |
> | Większe niż | Sprawdza czy lewy > prawy | 5 > 3 → true |
< | Mniejsze niż | Sprawdza czy lewy < prawy | 3 < 5 → true |
>= | Większe lub równe | Sprawdza czy lewy >= prawy | 5 >= 5 → true |
<= | Mniejsze lub równe | Sprawdza czy lewy <= prawy | 3 <= 5 → true |
Przykłady z różnymi typami danych:
// Porównywanie liczb
int a = 10, b = 20;
Console.WriteLine($"{a} == {b}: {a == b}"); // False
Console.WriteLine($"{a} != {b}: {a != b}"); // True
Console.WriteLine($"{a} < {b}: {a < b}"); // True
Console.WriteLine($"{a} > {b}: {a > b}"); // False
// Porównywanie stringów
string imie1 = "Anna";
string imie2 = "ANNA";
string imie3 = "Anna";
Console.WriteLine($"'{imie1}' == '{imie2}': {imie1 == imie2}"); // False (wielkość liter)
Console.WriteLine($"'{imie1}' == '{imie3}': {imie1 == imie3}"); // True
// Porównywanie bez uwzględniania wielkości liter
bool rowneIgnoreCase = string.Equals(imie1, imie2, StringComparison.OrdinalIgnoreCase);
Console.WriteLine($"Równe (ignore case): {rowneIgnoreCase}"); // True
// Porównywanie znaków
char litera1 = 'A';
char litera2 = 'B';
Console.WriteLine($"'{litera1}' < '{litera2}': {litera1 < litera2}"); // True (kod ASCII)
// Porównywanie bool
bool prawda = true;
bool fałsz = false;
Console.WriteLine($"{prawda} == {fałsz}: {prawda == fałsz}"); // FalsePułapki przy porównywaniu:
// Problem z liczbami zmiennoprzecinkowymi
double x = 0.1 + 0.2;
double y = 0.3;
Console.WriteLine($"0.1 + 0.2 == 0.3: {x == y}"); // Może być False!
// Bezpieczne porównywanie double
bool bliskoRowne = Math.Abs(x - y) < 0.0001;
Console.WriteLine($"Bezpieczne porównanie: {bliskoRowne}"); // True
// Porównywanie null
string tekst1 = null;
string tekst2 = "Hello";
// Console.WriteLine(tekst1 == tekst2); // OK - zwróci false
// Console.WriteLine(tekst1.Equals(tekst2)); // BŁĄD! NullReferenceException4. Operatory logiczne
Służą do łączenia lub modyfikowania wyrażeń logicznych (bool).
Podstawowe operatory logiczne:
| Operator | Nazwa | Opis | Przykład |
|---|---|---|---|
&& | AND (i) | True gdy oba operandy są True | true && false → false |
|| | OR (lub) | True gdy przynajmniej jeden operand jest True | true || false → true |
! | NOT (nie) | Odwraca wartość logiczną | !true → false |
Tabela prawdy:
| A | B | A && B | A || B | !A |
|---|---|---|---|---|
| true | true | true | true | false |
| true | false | false | true | false |
| false | true | false | true | true |
| false | false | false | false | true |
Praktyczne przykłady:
// Sprawdzanie dostępu do systemu
int wiek = 20;
bool maLicencje = true;
bool jestTrzezwy = true;
// Wszystkie warunki muszą być spełnione (AND)
bool mozeProwadzic = (wiek >= 18) && maLicencje && jestTrzezwy;
Console.WriteLine($"Może prowadzić: {mozeProwadzic}"); // True
// Przynajmniej jeden warunek musi być spełniony (OR)
bool jestWeekend = false;
bool jestUrlopze = true;
bool maWolne = jestWeekend || jestUrlopze;
Console.WriteLine($"Ma wolne: {maWolne}"); // True
// Negacja (NOT)
bool padaDeszcz = true;
bool słonecznaDzien = !padaDeszcz;
Console.WriteLine($"Słoneczny dzień: {słonecznaDzien}"); // FalseShort-circuit evaluation (ocena z przerwaniem):
int x = 0;
int y = 10;
// && przerywa gdy pierwszy warunek jest false
bool wynik1 = (x != 0) && (y / x > 2); // Drugi warunek NIE zostanie sprawdzony
Console.WriteLine($"Wynik 1: {wynik1}"); // False, bez błędu dzielenia przez 0
// || przerywa gdy pierwszy warunek jest true
bool admin = true;
bool superUser = false;
bool maUprawnienia = admin || (superUser && SprawdzUprawnienia());
// SprawdzUprawnienia() NIE zostanie wywołana, bo admin == true
static bool SprawdzUprawnienia()
{
Console.WriteLine("Sprawdzanie uprawnień..."); // Nie zostanie wyświetlone
return true;
}Złożone wyrażenia logiczne:
int temperatura = 22;
bool deszcz = false;
bool wiatr = true;
bool weekend = true;
// Skomplikowany warunek na wyjście na zewnątrz
bool dobryDzien = (temperatura > 15 && temperatura < 30) && // Odpowiednia temperatura
!deszcz && // Nie pada
(!wiatr || temperatura > 20) && // Nie wieje LUB jest ciepło
weekend; // Jest weekend
Console.WriteLine($"Dobry dzień na spacer: {dobryDzien}");
// Logika De Morgana - równoważne wyrażenia:
bool a = true, b = false;
// !(a && b) == (!a || !b)
bool wyrażenie1 = !(a && b); // !(true && false) = !false = true
bool wyrażenie2 = !a || !b; // !true || !false = false || true = true
Console.WriteLine($"De Morgan 1: {wyrażenie1 == wyrażenie2}"); // True
// !(a || b) == (!a && !b)
bool wyrażenie3 = !(a || b); // !(true || false) = !true = false
bool wyrażenie4 = !a && !b; // !true && !false = false && true = false
Console.WriteLine($"De Morgan 2: {wyrażenie3 == wyrażenie4}"); // True5. Operatory warunkowe
Operator warunkowy (ternary operator) ? :
Składnia: warunek ? wartość_jeśli_true : wartość_jeśli_false
int wiek = 17;
// Tradycyjne if-else
string status1;
if (wiek >= 18)
status1 = "pełnoletni";
else
status1 = "niepełnoletni";
// Operator warunkowy - krócej
string status2 = (wiek >= 18) ? "pełnoletni" : "niepełnoletni";
Console.WriteLine($"Status: {status2}");
// Inne przykłady
int a = 10, b = 20;
int maksimum = (a > b) ? a : b; // zwraca większą liczbę
string pogoda = "słonecznie";
string ubiór = (pogoda == "deszcz") ? "kurtka przeciwdeszczowa" : "lekka koszulka";
// Zagnieżdżone operatory warunkowe (ostrożnie z czytelnością!)
int punkty = 85;
string ocena = (punkty >= 90) ? "A" :
(punkty >= 80) ? "B" :
(punkty >= 70) ? "C" : "F";
Console.WriteLine($"Ocena: {ocena}");Null-coalescing operator ??
string tekst = null;
string domyślnyTekst = "Wartość domyślna";
// Tradycyjnie
string wynik1 = (tekst != null) ? tekst : domyślnyTekst;
// Z operatorem ?? - krócej
string wynik2 = tekst ?? domyślnyTekst;
Console.WriteLine($"Wynik: {wynik2}"); // "Wartość domyślna"
// Przykład praktyczny
string nazwaSerwera = GetServerName() ?? "localhost";
int portSerwera = GetServerPort() ?? 8080;
static string GetServerName() => null; // Symulacja braku konfiguracji
static int? GetServerPort() => null; // Zwraca nullable intNull-conditional operator ?. (C# 6.0+)
string tekst = null;
Person osoba = null;
// Tradycyjne sprawdzanie null
int długość1 = (tekst != null) ? tekst.Length : 0;
// Z operatorem ?. - bezpieczniej
int? długość2 = tekst?.Length; // null jeśli tekst == null
int długość3 = tekst?.Length ?? 0; // 0 jeśli tekst == null
// Łańcuchowe wywołania
string miasto = osoba?.Address?.City ?? "Nieznane miasto";
Console.WriteLine($"Miasto: {miasto}");
public class Person
{
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
}6. Operatory typu
Operator is – sprawdzanie typu
object wartość = "Hello World";
// Tradycyjne sprawdzanie typu
if (wartość is string)
{
string tekst = (string)wartość;
Console.WriteLine($"To string o długości: {tekst.Length}");
}
// Pattern matching (C# 7.0+) - jednocześnie sprawdza i rzutuje
if (wartość is string str)
{
Console.WriteLine($"To string: {str}");
}
// Z dodatkowymi warunkami
if (wartość is string s && s.Length > 5)
{
Console.WriteLine($"To długi string: {s}");
}
// Przykłady z różnymi typami
object[] różneWartości = { 42, "tekst", 3.14, true };
foreach (object item in różneWartości)
{
switch (item)
{
case int liczba:
Console.WriteLine($"Liczba całkowita: {liczba}");
break;
case string tekst:
Console.WriteLine($"Tekst: {tekst}");
break;
case double rzeczywista:
Console.WriteLine($"Liczba rzeczywista: {rzeczywista}");
break;
case bool logiczna:
Console.WriteLine($"Wartość logiczna: {logiczna}");
break;
default:
Console.WriteLine($"Nieznany typ: {item}");
break;
}
}Operator as – bezpieczne rzutowanie
object wartość = "Hello";
// Tradycyjne rzutowanie - może rzucić wyjątek
string tekst1 = (string)wartość; // OK
object liczba = 42;
// string tekst2 = (string)liczba; // InvalidCastException!
// Bezpieczne rzutowanie z 'as' - zwraca null przy niepowodzeniu
string tekst3 = liczba as string; // null (bez wyjątku)
if (tekst3 != null)
{
Console.WriteLine($"Udało się: {tekst3}");
}
else
{
Console.WriteLine("Nie udało się rzutować na string");
}
// Praktyczny przykład
object[] obiekty = { "Hello", 123, "World", 45.6 };
foreach (object obj in obiekty)
{
string jakisTekst = obj as string;
if (jakisTekst != null)
{
Console.WriteLine($"String: {jakisTekst}");
}
}Operator typeof – informacje o typie
// Pobieranie informacji o typie
Type typInt = typeof(int);
Type typString = typeof(string);
Type typDateTime = typeof(DateTime);
Console.WriteLine($"Nazwa typu int: {typInt.Name}");
Console.WriteLine($"Pełna nazwa: {typInt.FullName}");
// Porównywanie typów
object wartość = 42;
Type typWartości = wartość.GetType();
if (typWartości == typeof(int))
{
Console.WriteLine("To jest int");
}
// Sprawdzanie właściwości typu
if (typInt.IsValueType)
Console.WriteLine("int to typ wartościowy");
if (!typString.IsValueType)
Console.WriteLine("string to typ referencyjny");7. Operatory bitowe
Operują na poziomie pojedynczych bitów w reprezentacji binarnej liczb.
Podstawowe operatory bitowe:
| Operator | Nazwa | Opis |
|---|---|---|
& | Bitowe AND | Bit wynikowy = 1 gdy oba bity = 1 |
| | Bitowe OR | Bit wynikowy = 1 gdy przynajmniej jeden bit = 1 |
^ | Bitowe XOR | Bit wynikowy = 1 gdy bity są różne |
~ | Bitowe NOT | Odwraca wszystkie bity |
<< | Przesunięcie w lewo | Przesuwa bity w lewo |
>> | Przesunięcie w prawo | Przesuwa bity w prawo |
// Przykłady operacji bitowych
byte a = 12; // 00001100 w binarnym
byte b = 10; // 00001010 w binarnym
byte andWynik = (byte)(a & b); // 00001000 = 8
byte orWynik = (byte)(a | b); // 00001110 = 14
byte xorWynik = (byte)(a ^ b); // 00000110 = 6
byte notWynik = (byte)(~a); // 11110011 = 243 (w byte)
Console.WriteLine($"a & b = {andWynik}"); // 8
Console.WriteLine($"a | b = {orWynik}"); // 14
Console.WriteLine($"a ^ b = {xorWynik}"); // 6
Console.WriteLine($"~a = {notWynik}"); // 243
// Przesunięcia bitowe
int liczba = 5; // 00000101
int przesuniętaLewo = liczba << 2; // 00010100 = 20 (5 * 2^2)
int przesuniętaPrawo = liczba >> 1; // 00000010 = 2 (5 / 2^1)
Console.WriteLine($"{liczba} << 2 = {przesuniętaLewo}"); // 20
Console.WriteLine($"{liczba} >> 1 = {przesuniętaPrawo}"); // 2Praktyczne zastosowania operatorów bitowych:
// Flagi (enum z atrybutem [Flags])
[Flags]
enum FileAccess
{
None = 0, // 000
Read = 1, // 001
Write = 2, // 010
Execute = 4 // 100
}
// Łączenie uprawnień
FileAccess uprawnienia = FileAccess.Read | FileAccess.Write; // 011 = 3
Console.WriteLine($"Uprawnienia: {uprawnienia}");
// Sprawdzanie czy ma określone uprawnienie
bool czyMozeOdczytywac = (uprawnienia & FileAccess.Read) == FileAccess.Read;
Console.WriteLine($"Może odczytywać: {czyMozeOdczytywac}");
// Usuwanie uprawnienia
uprawnienia = uprawnienia & ~FileAccess.Write; // Usuń Write
Console.WriteLine($"Po usunięciu Write: {uprawnienia}");
// Przełączanie uprawnienia (toggle)
uprawnienia = uprawnienia ^ FileAccess.Execute; // Dodaj/usuń Execute
Console.WriteLine($"Po przełączeniu Execute: {uprawnienia}");8. Inne przydatne operatory
Operator sizeof
// Rozmiar typów wartościowych w bajtach
Console.WriteLine($"sizeof(bool): {sizeof(bool)} bajtów"); // 1
Console.WriteLine($"sizeof(byte): {sizeof(byte)} bajtów"); // 1
Console.WriteLine($"sizeof(int): {sizeof(int)} bajtów"); // 4
Console.WriteLine($"sizeof(long): {sizeof(long)} bajtów"); // 8
Console.WriteLine($"sizeof(float): {sizeof(float)} bajtów"); // 4
Console.WriteLine($"sizeof(double): {sizeof(double)} bajtów"); // 8
Console.WriteLine($"sizeof(decimal): {sizeof(decimal)} bajtów"); // 16Operator nameof (C# 6.0+)
string zmiennaName = "test";
int liczba = 42;
// Pobiera nazwę zmiennej/metody/typu jako string
Console.WriteLine(nameof(zmiennaName)); // "zmiennaName"
Console.WriteLine(nameof(liczba)); // "liczba"
Console.WriteLine(nameof(Console)); // "Console"
Console.WriteLine(nameof(Console.WriteLine)); // "WriteLine"
// Przydatne w logowaniu i debugowaniu
void LogError(string parameterName)
{
Console.WriteLine($"Błąd w parametrze: {parameterName}");
}
// Użycie
LogError(nameof(zmiennaName)); // "Błąd w parametrze: zmiennaName"Kolejność wykonywania operatorów (precedencja)
Gdy w wyrażeniu występuje kilka operatorów, ważna jest kolejność ich wykonywania:
Tabela precedencji (od najwyższej do najniższej):
- Operatory podstawowe:
(),[],.,?. - Operatory unarne:
+,-,!,~,++,--,(typ) - Mnożenie, dzielenie:
*,/,% - Dodawanie, odejmowanie:
+,- - Przesunięcia:
<<,>> - Porównania:
<,>,<=,>=,is,as - Równość:
==,!= - Bitowe AND:
& - Bitowe XOR:
^ - Bitowe OR:
| - Logiczne AND:
&& - Logiczne OR:
|| - Operatory warunkowe:
?:,?? - Przypisanie:
=,+=,-=,*=,/=,%=
Przykłady precedencji:
// Bez nawiasów - precedencja naturalna
int wynik1 = 2 + 3 * 4; // 2 + (3 * 4) = 14
int wynik2 = 10 / 2 + 3; // (10 / 2) + 3 = 8
bool wynik3 = 5 > 3 && 2 < 4; // (5 > 3) && (2 < 4) = true
// Z nawiasami - wymuszona kolejność
int wynik4 = (2 + 3) * 4; // (2 + 3) * 4 = 20
int wynik5 = 10 / (2 + 3); // 10 / (2 + 3) = 2
Console.WriteLine($"2 + 3 * 4 = {wynik1}"); // 14
Console.WriteLine($"(2 + 3) * 4 = {wynik4}"); // 20