Częste błędy początkujących w programowaniu obiektowym w języku C#

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
    }
}