A konstruktor objektumok esetén egy speciális metódus, amely az objektum létrehozásakor fut le. Szerepe az osztályon belüli változók kezdőértékének beállÃtása. Minden osztály legalább egy konstruktor metódust tartalmaz. Ha nem definiáljuk ezt a metódust, akkor a fordÃtó generál egyet, ami paraméter nélküli lesz.
Ha az osztály rendelkezik már egy konstruktorral (paraméteres vagy paraméter nélküli), akkor a frodÃtó nem generál az osztályhoz paraméter nélküli konstruktort. Struktúrák esetén a paraméter nélküli alapértelmezett konstruktort minden esetben a fordÃtó fogja generálni. A konstruktorok jellemzÅ‘i:
- nincs visszatérési értékük (void kulcsszó sem kell eléjük)
- nevük megegyezik az osztály nevével
- fogadhatnak paramétereket
- több is lehet belÅ‘lük, viszont paraméterek számában és tÃpusában egyértelműen megkülönböztethetÅ‘nek kell lennie két konstruktornak
A hozzáférési szintek konstruktorok esetén szintén szabályozhatóak, viszont, ha csak egy privát vagy védett elérésű konstruktorral rendelkezik az osztályunk, akkor nem lesz példányosÃtható. Ennek szerepe akkor van, ha az osztály példányosÃtását nem szeretnénk közvetlenül megengedni. Egyes tervezési minták épÃtenek erre. Ennek a megoldásnak nagyobb szerepe régebbi .NET verziók esetén volt.
Például akkor, amikor egy olyan osztályt szerettünk volna létrehozni, amely csak statikus elérésű metódusokat tartalmaz. Ebben az esetben ugyebár nincs értelme a példányosÃtásnak, ilyenkor jó választás lehet a privát konstruktor. Viszont késÅ‘bb erre a célra bevezették a statikus osztály fogalmát. A statikus osztály a static kulcsszóval van kiegészÃtve. Ez azt jelzi a fordÃtónak, hogy az osztály nem példányosÃtható. BelsÅ‘ működésében egyébként a static megjelölésű osztályt úgy fordÃtja a fordÃtó, hogy annak a konstruktora privát elérésű legyen.
Az alábbi példa a konstruktorok használatát mutatja be egy egyszerű osztályon:
using System;
namespace PeldaKonstruktorok
{
class KonstruktorPelda
{
private int _szam;
//paraméter nélküli konstruktor
public KonstruktorPelda()
{
_szam = 42;
}
//paraméteres konstruktor
public KonstruktorPelda(int szam)
{
_szam = szam;
}
public void Kiir()
{
Console.WriteLine(_szam);
}
}
class Program
{
static void Main(string[] args)
{
var a = new KonstruktorPelda();
var b = new KonstruktorPelda(33);
a.Kiir();
b.Kiir();
Console.ReadKey();
}
}
}
A program kimenete:
42
33
A példában jól látható, hogy az osztályok példányosÃtása a new kulcsszóval történik, amit az osztály neve követ. Az osztálynév után pedig zárójelben a konstruktornak átadott paraméterek következnek. A jelenlegi példa definiál egy paraméter nélkülit, aminek a meghÃvásakor az objektum belsejében tárolt szám változó értéke 42 lesz.
A paraméteres változat pedig a paraméterként kapott értéket teszi bele a belsÅ‘ szám változóba. A belsÅ‘, privát változók neveit én személy szerint alulvonás karakterrel szeretem kezdeni. Ilyen módon azonnal látható az automatikus kód kiegészÃtésben a változó nevébÅ‘l a szerepköre.
A konstruktorok hÃvása egymáshoz láncolható. Ez azt jelenti, hogy nem kell redundáns1 kódot Ãrnunk.
A redundáns kód karbantarthatósági szempontból káros. Ha egy helyen elrontunk valamit a programunkban és azt másoljuk különbözÅ‘ részekre, akkor bizony igen nehéz lesz a hibát konzisztensen kijavÃtani, mivel többször is szerepel ugyanaz a hibás részlet a programunkban. Az alábbi példakód az elÅ‘bbi paraméteres konstruktor esetén mutatja be a konstruktorok láncolásának lehetÅ‘ségét.
using System;
namespace PeldaKonstruktorok2
{
class KonstruktorPelda
{
private int _szam;
//paraméter nélküli konstruktor
public KonstruktorPelda() : this(42)
{
//Ha ide kódot tennénk, akkor az a Paraméteres
//konstruktor futása után futna le
}
//paraméteres konstruktor
public KonstruktorPelda(int szam)
{
_szam = szam;
}
public void Kiir()
{
Console.WriteLine(_szam);
}
}
class Program
{
static void Main(string[] args)
{
var a = new KonstruktorPelda();
var b = new KonstruktorPelda(33);
a.Kiir();
b.Kiir();
Console.ReadKey();
}
}
}
A program kimenete:
42
33
A módosÃtott példa ugyanúgy működik, mint az elÅ‘zÅ‘, azonban itt a paraméter nélküli konstruktor lefutáskor meghÃvja az egy paraméteres konstruktort 42 értékkel, ami beállÃtja az értéket. A hivatkozás egy új kulcsszóval történik, amely a this. A this kulcsszó egy osztályon belül minden esetben az adott osztályra mutat.
Jelen esetben a példa nem tesz sok hasznosat, mivel igen rövid a konstruktor kód. Viszont elÅ‘fordulhat olyan eset, hogy a konstruktor kódunk igen hosszúra nyúlik és ráadásul több változatra is szükségünk van. Ezen esetekben igen ajánlott a konstruktor hÃvások láncolása.
A this kulcsszó használata
Felmerülhet egyébként a kérdés, hogy a this kulcsszót milyen esetekben érdemes használni? A kérdés megválaszolására egy példát mutatnék:
class pelda
{
private int a;
private int b;
pelda(int a, int b)
{
a = a;
b = b;
}
}
Ezen rövid példakód nem teljesen azt csinálja, amit szeretnénk. Nyilvánvalóan azt szeretnénk, hogy a konstruktor a paramétereként kapott a és b számot az objektum belső a és b változójába másolja.
Azonban a konstruktoron belül a változók hatóköre miatt kicsit másként működik a dolog. Mivel az osztály tagváltozóinak azonos a neve az argumentumokban használt változókkal, Ãgy a fordÃtó azt fogja feltételezni, hogy a paraméterként kapott a változót egyenlÅ‘vé kell tennie a paraméterként kapott a változóval. Ez a működés azért következik be, mert a metódusban használt változók névfeloldása a metódusra koncentrálódik.
Az alábbi kód a helyesen működő változat:
class pelda
{
private int a;
private int b;
pelda(int a, int b)
{
this.a = a;
this.b = b;
}
}
A this kulcsszó használatával explicit megmondhatjuk a kódunkban, hogy fordÃtáskor hogyan is értelmezendÅ‘ az adott kódrészlet.
Tehát a this használata az osztály adattagjainak elérése esetén akkor kötelező, ha az adott hatókörön belül nem egyértelmű a névfeloldás és csak explicit módon jelezhető, hogy mit is szeretnénk. Többek között ezért is hasznos az alábbi kódolási konvenciók betartása:
- A metódusok definÃciójában szereplÅ‘ paraméter változóneveket Ãrjuk kisbetűkkel.
- Az osztály adattagjainak és metódusainak nevét tevepúpos Ãrással Ãrjuk, vagy a privát adattagokat jelöljük nevük kezdetén aláhúzás karakterekkel.
Statikus konstruktor
A statikus osztályok és a nem statikus osztályok is rendelkezhetnek egy statikus konstruktorral. A statikus konstruktor ebben az esetben az osztályunk bármely statikus tagjának elsÅ‘ használata elÅ‘tt fog közvetlenül lefutni. A statikus konstruktorból csak egy lehet, paramétert nem fogadhat. Nem lehet ellátni elérés módosÃtóval és közvetlenül nem lehet meghÃvni.
Ha az osztály rendelkezik statikus és nem statikus konstruktorral, akkor a statikus konstruktorban elhelyezett kód a nem statikus konstruktor kódja elÅ‘tt fog futni, az osztály elsÅ‘ példányosÃtásakor egy alkalommal.
Az alábbi példa a statikus konstruktor használatát mutatja be:
using System;
namespace PeldaStaticKonstruktor
{
static class Pelda
{
private static int _szam;
//statikus konstruktor
static Pelda()
{
_szam = 5;
}
public static void TesztMetodus()
{
Console.WriteLine("Még ennyi van hátra: {0}", Szam);
--_szam;
}
}
class Program
{
static void Main(string[] args)
{
for (int i=0; i<5; i++)
{
Pelda.TesztMetodus();
}
Console.ReadKey();
}
}
}
A program kimenete:
Még ennyi van hátra: 5
Még ennyi van hátra: 4
Még ennyi van hátra: 3
Még ennyi van hátra: 2
Még ennyi van hátra: 1
-
új információt nem tartalmazó, ismétlÅ‘dÅ‘↩