1. Proste konstruktory
Konstruktor — to specjalna metoda klasy, która wywołuje się automatycznie przy tworzeniu obiektu. Inicjalizuje (ustawia) obiekt: nadaje wartości początkowe, robi walidacje, może nawet poprawić ci humor, jeśli napiszesz w nim żart.
Konstruktor pozwala ci od razu stworzyć obiekt w określonym stanie, zamiast ustawiać wszystkie jego dane pojedynczo przez pola i właściwości ręcznie. To wygodne i bezpieczne, bo od razu podajesz wszystkie ważne parametry — i nie zapomnisz o czymś krytycznym.
Bez konstruktora kod może wyglądać topornie i być podatny na błędy:
Person p = new Person();
p.Name = "Julia";
p.Age = 25; // A co jeśli zapomnimy podać wiek?
Z konstruktorem:
Person p = new Person("Julia", 25); // Wszystko przekazane od razu i obiekt gotowy do życia!
Składnia konstruktora
Konstruktor — to specjalna "metoda", której nazwa dokładnie pokrywa się z nazwą klasy i która nie ma wartości zwracanej (nawet void). Tak wygląda konstruktor domyślny:
public class Person
{
// Konstruktor domyślny (bez parametrów)
public Person()
{
// Tu możesz napisać kod inicjalizacji
}
}
Konstruktor domyślny — to taki niewidzialny "pomocnik", który nie przyjmuje żadnych parametrów i po prostu ustawia wszystkie pola i właściwości twojej klasy na ich wartości domyślne:
- Dla typów liczbowych (int, double, float itd.) to będzie 0.
- Dla typu logicznego (bool) to false.
- Dla typów referencyjnych (string, inne klasy) to null (czyli "nic", "brak referencji do obiektu").
- Dla DateTime to będzie 01.01.0001 00:00:00.
Jak wywołać konstruktor?
Właściwie, kiedy piszesz operator new przy tworzeniu obiektu, wywołujesz konstruktor!
Person p = new Person();
Jeśli nie zdefiniujesz jawnie żadnego konstruktora, kompilator C# stworzy dla ciebie konstruktor domyślny (bez parametrów). Ale jeśli zadeklarujesz choć jeden własny — konstruktor domyślny znika i kompilator poprosi cię, żebyś dodał go ręcznie, jeśli go potrzebujesz.
Przykład
Dodajmy konstruktor do klasy naszej aplikacji. Oto prosta wersja klasy studenta:
public class Student
{
public string Name;
public int Age;
// Konstruktor z dwoma parametrami (imię i wiek)
public Student(string name, int age)
{
Name = name; // Przypisujemy wartość do pola
Age = age;
}
}
Teraz możesz stworzyć studenta tak:
Student s = new Student("Jan", 21);
Console.WriteLine($"{s.Name}: {s.Age} lat"); // Jan: 21 lat
- Zadeklarowaliśmy konstruktor o tej samej widoczności (public), co sama klasa.
- W konstruktorze przypisujemy wartości polom, używając przekazanych parametrów.
- Taki sposób chroni przed zapominalstwem: kompilator wymusi podanie imienia i wieku przy tworzeniu obiektu.
2. Parametry konstruktora
W C# możesz zadeklarować kilka konstruktorów z różnymi zestawami parametrów. To się nazywa przeciążenie konstruktora (o przeciążaniu metod jeszcze pogadamy później).
Na przykład, dodajmy konstruktor bez parametrów:
public class Student
{
public string Name;
public int Age;
// Konstruktor domyślny
public Student()
{
Name = "Bez imienia";
Age = 0;
}
// Konstruktor z parametrami
public Student(string name, int age)
{
Name = name;
Age = age;
}
}
Teraz oba warianty są możliwe:
Student s1 = new Student(); // Imię: Bez imienia, wiek: 0
Student s2 = new Student("Ola", 22); // Imię: Ola, wiek: 22
Użycie konstruktora do walidacji
Konstruktor — świetne miejsce, żeby sprawdzać "jakość" przekazywanych danych. Na przykład, student nie może mieć ujemnego wieku!
public Student(string name, int age)
{
if (age < 0)
throw new ArgumentException("Wiek nie może być ujemny!");
Name = name;
Age = age;
}
Teraz jeśli ktoś spróbuje stworzyć studenta Student("Maluch", -2), aplikacja rzuci wyjątek (ArgumentException). Takie podejście często się stosuje dla "żelaznej" niezawodności danych.
3. Inicjalizacja złożonych obiektów
Często w prawdziwych aplikacjach jeden obiekt może "składać się" nie tylko z prymitywów, ale też zawierać inne obiekty:
public class Group
{
public string GroupName;
public Student[] Students;
public Group(string groupName, Student[] students)
{
GroupName = groupName;
Students = students;
}
}
Teraz łatwo stworzyć grupę z zestawem studentów:
var students = new Student[]
{
new Student("Jan", 20),
new Student("Maria", 19)
};
Group g = new Group("Grupa-101", students);
Inicjalizacja pól domyślnych
Czasem chcesz ustawić wartości domyślne dla niektórych pól, jeśli nie wszystkie parametry trafiają do konstruktora. Na przykład, jeśli e-mail nie jest obowiązkowy:
public Student(string name, int age)
{
Name = name;
Age = age;
Email = "unknown@noemail.com"; // Wartość domyślna
}
4. Inicjalizacja przez Object Initializer
Konstruktory możesz łączyć z inną wygodną składnią — inicjalizatorami obiektów. Możesz wywołać konstruktor, a potem w klamrach podać wartości właściwości nowego obiektu:
public class Student
{
public string Name { get; set; }
public int Age { get; set; }
public string Email { get; set; }
// Konstruktor i tak jest zalecany
public Student(string name, int age)
{
Name = name;
Age = age;
Email = "";
}
}
Student s = new Student("Antoni", 18) { Email = "antoni@domain.com" }; // konstruktor + właściwości
Ta składnia świetnie się sprawdza, gdy część parametrów ma wartości domyślne albo nie zawsze są znane przy tworzeniu.
5. Typowe błędy i niuanse
Pracując z konstruktorami, początkujący często trafiają na kilka popularnych błędów. Ogarniemy je na luzie:
Błąd nr 1: Niezgodność nazw
Czasem mylą się nazwy parametrów i pól, zwłaszcza jeśli różnią się tylko wielkością liter.
public Student(string Name, int Age) // Z wielkiej litery!
{
Name = Name; // Ups! Oba Name odnoszą się do parametru. Pole zostanie nieustawione.
}
Jak poprawnie: Użyj this żeby odwołać się do pola obiektu:
public Student(string name, int age)
{
this.Name = name;
this.Age = age;
}
Albo po prostu wybieraj różne nazwy (np. nameParam, ageParam), ale praktyka z this. jest uznawana za dobry styl, szczególnie w większych projektach.
Błąd nr 2: Brak konstruktora domyślnego
Jeśli zadeklarowałeś choć jeden konstruktor, a potem próbujesz stworzyć obiekt bez parametrów — dostaniesz błąd kompilacji:
public class Student
{
public Student(string name) { /*...*/ }
}
// gdzieś w kodzie
Student s = new Student(); // Błąd! Brak konstruktora bez parametrów.
Rozwiązanie: Jawnie dodaj konstruktor bez parametrów:
public Student() { /*...*/ }
Błąd nr 3: Nieskończona rekursja — jeśli konstruktor wywołuje sam siebie
public Student()
{
// Błąd! Wywołuje sam siebie — nieskończona rekursja.
new Student();
}
GO TO FULL VERSION