Wprowadzenie
Początkujący programiści często popełniają charakterystyczne błędy podczas nauki programowania obiektowego. Poznanie tych błędów i sposobów ich unikania znacznie przyspiesza proces nauki i pomaga pisać lepszy, bardziej niezawodny kod.
1. Mylenie klasy z obiektem
❌ Błędne myślenie:
Wielu początkujących myśli, że klasa i obiekt to to samo.
✅ Prawidłowe zrozumienie:
- Klasa = przepis, wzór, szablon
- Obiekt = konkretny przedmiot stworzony według tego przepisu
Przykład:
// To jest KLASA - przepis na samochód
class Samochod
{
public string Marka;
public string Model;
}
class Program
{
static void Main()
{
// To są OBIEKTY - konkretne samochody
Samochod samochod1 = new Samochod(); // Pierwszy samochód
Samochod samochod2 = new Samochod(); // Drugi samochód
// Każdy obiekt ma swoje własne wartości
samochod1.Marka = "Toyota";
samochod2.Marka = "Ford";
Console.WriteLine(samochod1.Marka); // Toyota
Console.WriteLine(samochod2.Marka); // Ford
}
}2. Zapominanie o słowie kluczowym new
❌ Błędny kod:
class Uczen
{
public string Imie;
public int Wiek;
}
class Program
{
static void Main()
{
Uczen uczen; // Tylko deklaracja, bez utworzenia obiektu
uczen.Imie = "Jan"; // BŁĄD! Obiekt nie został utworzony
}
}✅ Poprawny kod:
class Program
{
static void Main()
{
Uczen uczen = new Uczen(); // Utworzenie obiektu
uczen.Imie = "Jan"; // Teraz to działa poprawnie
uczen.Wiek = 16;
}
}Wyjaśnienie:
Bez słowa new mamy tylko referencję do obiektu, ale sam obiekt nie istnieje w pamięci.
3. Nierozumienie null i NullReferenceException
❌ Błędny kod:
class Ksiazka
{
public string Tytul;
public int LiczbaStron;
}
class Program
{
static void Main()
{
Ksiazka mojaKsiazka = null; // Referencja wskazuje na "nic"
Console.WriteLine(mojaKsiazka.Tytul); // BŁĄD! NullReferenceException
}
}✅ Poprawny kod:
class Program
{
static void Main()
{
Ksiazka mojaKsiazka = new Ksiazka(); // Utworzenie obiektu
mojaKsiazka.Tytul = "Wiedźmin";
Console.WriteLine(mojaKsiazka.Tytul); // Działa poprawnie
// Lub sprawdzenie przed użyciem:
if (mojaKsiazka != null)
{
Console.WriteLine(mojaKsiazka.Tytul);
}
}
}4. Niepoprawne używanie konstruktora
❌ Błędny kod:
class Telefon
{
public string Marka;
public string Model;
// Konstruktor z błędem - nie zwraca void!
public void Telefon(string marka, string model) // BŁĄD!
{
Marka = marka;
Model = model;
}
}✅ Poprawny kod:
class Telefon
{
public string Marka;
public string Model;
// Poprawny konstruktor - bez typu zwracanego
public Telefon(string marka, string model)
{
Marka = marka;
Model = model;
}
}
class Program
{
static void Main()
{
Telefon telefon = new Telefon("Samsung", "Galaxy S21");
Console.WriteLine($"{telefon.Marka} {telefon.Model}");
}
}Ważne zasady konstruktora:
- Nazwa konstruktora musi być identyczna z nazwą klasy
- Konstruktor nie ma typu zwracanego (nawet
void) - Konstruktor jest wywoływany automatycznie przy tworzeniu obiektu
5. Nieprawidłowe używanie słowa kluczowego static
❌ Błędny kod:
class Kalkulator
{
public int wynik; // Pole niestatyczne
public static void Dodaj(int a, int b)
{
wynik = a + b; // BŁĄD! Metoda statyczna nie może używać pól niestatycznych
}
}✅ Poprawny kod – opcja 1 (wszystko niestatyczne):
class Kalkulator
{
public int wynik;
public void Dodaj(int a, int b)
{
wynik = a + b;
}
}
class Program
{
static void Main()
{
Kalkulator kalk = new Kalkulator();
kalk.Dodaj(5, 3);
Console.WriteLine(kalk.wynik); // 8
}
}✅ Poprawny kod – opcja 2 (metoda statyczna):
class Kalkulator
{
public static int Dodaj(int a, int b)
{
return a + b; // Zwraca wynik zamiast go przechowywać
}
}
class Program
{
static void Main()
{
int wynik = Kalkulator.Dodaj(5, 3); // Wywołanie na klasie, nie obiekcie
Console.WriteLine(wynik); // 8
}
}6. Brak enkapsulacji – wszystko public
❌ Błędny kod:
class KontoBankowe
{
public double saldo; // Każdy może zmienić saldo!
public string numerKonta;
public void Wyplac(double kwota)
{
saldo -= kwota;
}
}
class Program
{
static void Main()
{
KontoBankowe konto = new KontoBankowe();
konto.saldo = 1000000; // Ups! Można ustawić dowolne saldo
}
}✅ Poprawny kod:
class KontoBankowe
{
private double saldo; // Chronione pole
public string NumerKonta { get; set; }
public KontoBankowe(string numer)
{
NumerKonta = numer;
saldo = 0;
}
public void Wplac(double kwota)
{
if (kwota > 0)
saldo += kwota;
}
public bool Wyplac(double kwota)
{
if (kwota > 0 && kwota <= saldo)
{
saldo -= kwota;
return true;
}
return false;
}
public double PobierzSaldo()
{
return saldo;
}
}7. Niepoprawne porównywanie obiektów
❌ Błędny kod:
class Osoba
{
public string Imie;
public int Wiek;
}
class Program
{
static void Main()
{
Osoba osoba1 = new Osoba { Imie = "Jan", Wiek = 25 };
Osoba osoba2 = new Osoba { Imie = "Jan", Wiek = 25 };
if (osoba1 == osoba2) // BŁĄD! Porównuje referencje, nie wartości
{
Console.WriteLine("Te same osoby");
}
else
{
Console.WriteLine("Różne osoby"); // To się wypisze!
}
}
}✅ Poprawny kod:
class Program
{
static void Main()
{
Osoba osoba1 = new Osoba { Imie = "Jan", Wiek = 25 };
Osoba osoba2 = new Osoba { Imie = "Jan", Wiek = 25 };
// Porównanie właściwości
if (osoba1.Imie == osoba2.Imie && osoba1.Wiek == osoba2.Wiek)
{
Console.WriteLine("Te same dane");
}
// Lub porównanie referencji (czy to ten sam obiekt)
Osoba osoba3 = osoba1;
if (osoba1 == osoba3)
{
Console.WriteLine("To ten sam obiekt");
}
}
}8. Niepoprawne nazywanie klas i właściwości
❌ Błędne nazwy:
class samochod // Mała litera na początku
{
public string marka; // Właściwości również małą literą
public string MODEL; // Wszystkie wielkie litery
public int rok_produkcji; // Podkreślenia w C#
}✅ Poprawne nazwy (konwencja C#):
class Samochod // PascalCase dla klas
{
public string Marka { get; set; } // PascalCase dla właściwości publicznych
public string Model { get; set; }
public int RokProdukcji { get; set; }
private string numerVin; // camelCase dla pól prywatnych
}9. Tworzenie obiektów w pętli bez potrzeby
❌ Nieefektywny kod:
class Program
{
static void Main()
{
for (int i = 0; i < 5; i++)
{
Random rnd = new Random(); // Niepotrzebne tworzenie w każdej iteracji
Console.WriteLine(rnd.Next(1, 100));
}
}
}✅ Efektywny kod:
class Program
{
static void Main()
{
Random rnd = new Random(); // Jeden obiekt dla całej pętli
for (int i = 0; i < 5; i++)
{
Console.WriteLine(rnd.Next(1, 100));
}
}
}10. Niezrozumienie różnicy między właściwościami a polami
❌ Mieszanie pojęć:
class Prostokat
{
public double szerokosc; // To jest pole
public double wysokosc; // To też jest pole
// Pole do przechowywania powierzchni - błędne podejście
public double powierzchnia;
public void ObliczPowierzchnie()
{
powierzchnia = szerokosc * wysokosc;
}
}✅ Poprawne użycie właściwości:
class Prostokat
{
public double Szerokosc { get; set; } // Właściwość
public double Wysokosc { get; set; } // Właściwość
// Właściwość obliczana automatycznie
public double Powierzchnia
{
get { return Szerokosc * Wysokosc; }
}
}
class Program
{
static void Main()
{
Prostokat prostokat = new Prostokat();
prostokat.Szerokosc = 5;
prostokat.Wysokosc = 3;
Console.WriteLine($"Powierzchnia: {prostokat.Powierzchnia}"); // 15
}
}