A konstans
Ha azt szeretnénk, hogy egy primitív (beépített típusú) vagy enum változó értéke ne tudjon módosulni, hanem az egész programra nézve ugyanaz legyen mindig, akkor azt a változót meg kell jelölni a const kulcsszóval.
const float pi = 3.14f // Kör kerületének és átfogójának aránya
const float gravity = 9.81f; // Gravitációs gyorsulás m/s2
const int speedOfLight = 299792458; // Fény sebessége m/s
const string appName = "My App's Name"; // Alkalmazás neve
const float meterToFeet = 3.28084f; // Méter és a láb közti arányszám
pi = 4.13; // 🛑 ERROR: Konstanst akarunk megváltoztatni! 🛑
Bizonyos szinten ellentmondás az, hogy egy változó konstans. Most változik az értéke vagy sem?
Ez viszont csak a “változó” / “variable” elnevezés miatt van így. Pontosabban leírná a fogalmat, ha úgy hívnánk a változót, hogy “Nevesített objektum tároló”. Ennek azonban sajnos nem olyan jó a csengése. Ezért marad a változó, ami csak akkor hangzik furán ha éppen az konstans.
(Lokális változók és field-ek is lehetnek konstansok.)
Egy konstans változó csak egyszer van eltárolva a memóriában szemben a normál mezőkkel, amik annyiszor léteznek, ahány példány létezik az őket tartalmazó összetett típusból.
Vegyük a következő példát:
class Person // Személy osztály
{
public string name; // Személy neve
public int age; // Személy kora
public const int adulthoodAgeLimit = 18; // Nagykorúság határa KONSTANS
public bool IsAdult()
{
return age >= ageLimit;
}
}
// ...
Person person1 = new() { name = "Homer", age = 39};
Person person2 = new() { name = "Marge", age = 36};
Person person3 = new() { name = "Bart", age = 10};
Person person4 = new() { name = "Lisa", age = 8};
Person person5 = new() { name = "Maggie", age = 3};
A fenti kód leír egy Person
(személy) osztályt. Minden személynek van egy neve és egy kora.
Mivel 5 személyt hoztam létre ebből az osztályból, így 5 különböző kor változó létezik a memóriában. Minden személyhez egy.
Azonban a nagykorúság korhatára egy fix érték, mindenkire ugyanúgy igaz. Nem érdemes többször eltárolni és nem tartozik csak egy személyhez. Ezért osztályon kívülről nem az objektum-on, hanem az osztály nevén keresztül tudunk hivatkozni rá:
// Normál mező:
int ageOfLisa = person4.age; // Hivatkozás egy példányon keresztül
// Konstans:
int limitAge = Person.adulthoodAgeLimit; // Hivatkozás az osztály nevén keresztül
Mindebben a konstans “változó” nagyban hasonlít egy statikus tagra. Látsd: Statikus tagok és osztályok
readonly
: A csak olvasható mező
Konstansokat csak a C# beépített (primitív) típusaiból és enum-okból tudunk létrehozni.
Minden egyéb típusból hasonló célra érdemes lehet egy readonly
, azaz csak olvasható mezőt használni. Ezen fajta változónak csak egyszer az objektum létrejöttekor adhatunk értéket, ami aztán nem változhat. Ezt tehetjük közvetlen értékadással (a deklarációval egy sorban) vagy konstruktorral:
// Létrehozok két readonly vektort,
// amik egység hosszúak és 45 fokos szöget zárnak be minden tengellyel:
// Értékadás egyből deklarációvan egy sorban.
readonly Vector2 diagonal2 = new (1/Mathf.Sqrt(2), 1/Mathf.Sqrt(2));
// Értékadás konstruktorral:
readonly Vector3 diagonal3;
TestClass() // Konstruktor
{
float d = 1 / Mathf.Sqrt(3);
diagonal3 = new (d, d, d);
}
Gyakran a readonly
változó egyben static
is. Ekkor gyakorlatilag konstansként viselkedik.
Lehetséges statikus osztályokban statikus konstruktort is írni, ami egyszer fog lefutni mielőtt először használnánk az osztályt. Ebben beállíthatjuk az ilyen elemek értékeit. Pl.:
static class MyMath
{
public static readonly Vector2 diagonal2;
public static readonly Vector3 diagonal3;
MyMath() // statikus konstruktor
{
float d2 = 1 / Mathf.Sqrt(2);
diagonal2 = new (d3, d3);
float d3 = 1 / Mathf.Sqrt(3);
diagonal3 = new (d3, d3, d3);
}
}