Na początku stwórzmy strukturę z konstruktorem przyjmującym dwa parametry:
public struct SampleStruct { public SampleStruct(int x, int y) { _x = x; _y = y; } private int _x, _y; }
Czy powyższy kod jest prawidłowy? Tak, skompiluje się i będzie działał bez problemów. Zdefiniujmy więc domyślny konstruktor:
public struct SampleStruct { public SampleStruct() { _x = _y = 0; } public SampleStruct(int x, int y) { _x = x; _y = y; } private int _x, _y; }
W czasie kompilacji dostaniemy następujący błąd: “Structs cannot contain explicit parameterless constructors”. Dlaczego więc, w przeciwieństwie do klas, nie możemy implementować bezparametrowych konstruktorów?
Główną przyczyną jest fakt, że dla każdej struktury generowany jest już domyślny konstruktor, odpowiedzialny za inicjalizowanie wartości. Warto zaznaczyć, że jest to bardzo wydajny konstruktor. Rozważmy ponownie, inny problem z inicjalizacją:
public struct SampleStruct { public SampleStruct(int x) { _x = x; } public int _x, _y; }
Stworzyliśmy własny konstruktor inicjalizujący tylko jedno pole. Co się stanie podczas kompilacji? Oczywiście otrzymamy błąd: “Field ‘WindowsFormsApplication2.SampleStruct._y’ must be fully assigned before control is returned to the caller”. Inicjalizowanie wszystkich pól jest zatem obowiązkiem konstruktorów.
Wywołanie domyślnego konstruktora, zawsze gwarantuje wyzerowanie wszystkich pól w sposób bardzo efektywny. Załóżmy, że chcemy stworzyć dużą tablicę:
SampleStruct []array=new SampleStruct[5000];
Inicjalizacja tablicy struktur jest bardzo szybka – wystarczy zaalokować odpowiednią pamięć na stosie a następnie ją wyzerować (duża przewaga nad klasami). Gdyby CLR umożliwiał wywoływanie konstruktorów domyślnych stworzonych przez użytkownika, inicjalizacja byłaby po prostu wolniejsza. Najpierw nastąpiłaby alokacja pamięci a potem w drugiej pętli każdy konstruktor musiałby zostać wywołany – a w końcu w ValueType nie o to chodzi.
Tak naprawdę CLR pozwala na definiowanie domyślnych konstruktorów. Jednak i tak nie są one wywoływane (zawsze jest wywołana inicjalizacja wygenerowana przez kompilator). Z tego względu, c# ograniczył tą możliwość aby nie wprowadzać niepotrzebnego zamieszania.
Bardzo dobry tekst. W sumie takie niby nic ale może wystąpić na rozmowie kwalifikacyjnej.
Dobrze wiedzieć, dzięki. To teraz może, dlaczego konstruktor w statycznej klasie nie może mieć parametrów 😉
@Lukasz:
A jakbyś przekazał takie parametry?
Dobre 🙂