A C# korábbi változatai esetén a readonly kulcsszó csak tagváltozók esetén volt használható. Az Ãgy megjelölt tagváltozók csak a konstruktorban kaphatnak értéket és utána nem módosÃtható az értékük.
C# 8.0 óta azonban metódus elÅ‘tt is alkalmazható a readonly kulcsszó, de csak struktúrák esetén. A readonly módosÃtóval megjelölt metódus nem módosÃthatja az struktúra tagváltozóinak értékét. Ha erre mégis sor kerülne, akkor fordÃtási hibába ütközünk.
Felmerülhet a kérdés, hogy ez miért jó vagy miért hasznos? Az objektum orientált paradigma nem választja szét az adatokat és a hozzájuk kapcsolódó metódusokat, ezért ha egy külsÅ‘ gyártó struktúráját alkalmazzuk, akkor nem feltétlen tudjuk megmondani, hogy a metódus hÃvása az struktúra belsÅ‘ állapotát módosÃtja-e vagy sem. Ez a bizonytalanság problémákat tud okozni, ami a kód olvashatóságát és karbantarthatóságát nehezÃti.
Ezen problémák elhárÃtásában nagymértékben segÃt, ha tudjuk, vagy jelölve van valamilyen módon, hogy az adott metódus nem módosÃt állapotot. Nézzünk egy példát:
public struct Point
{
public double X { get; set; }
public double Y { get; set; }
public double Tavolsag => Math.Sqrt(X * X + Y * Y);
public readonly override string ToString()
{
//fordÃtási hiba
//Y = 22;
return $"({X}, {Y}) Távolsága az Origótól: {Tavolsag}";
}
}
A fenti struktúra definÃcióban a ToString() metódust megjelöltük a readonly kulcsszóval, mivel a ToString() hÃvás esetén a józan észnek ellent mondana, ha az állapottal babrálnánk.
A readonly elÅ‘nye, hogy a struktúra létrehozója a tervezési szándékot is közli. Ezért egy késÅ‘bbi módosÃtó esetleg elgondolkozik, hogy talán okkal lett a metódus readonly és nem kellene benne egy állapot módosÃtást eszközölni.
Ref readonly
A C# 12 egyik újdonsága a ref és a readonly kulcsszó kombinálhatósága. Ez egy csak olvasható, referencia alapú értékátadást teszt lehetővé. Ennek kapcsán felmerülhet a kérdés, hogy ennek mi értelme van?
Ez a funkció akkor nyer értelmet, ha van egy metódusunk, amit sokszor kell meghÃvnunk és ez a metódus érték tÃpusokat vár paraméterként. Ebben az esetben a metódus minden egyes hÃvásakor egy másolat keletkezik az argumentumokról. Ennek a másolásnak az idÅ‘költsége nem elhanyagolható már mondjuk milliós hÃvási szám esetén. Ha referencia szerint adjuk át a változókat, akkor a másolás költsége megspórolható, de cserébe veszélyes szituációt idézünk elÅ‘, mert a metóduson belül módosÃthatjuk a hÃvó értéket.
Ezen változtat a ref readonly kombinációja: referencia alapú átadást tudunk vele csinálni, de a metóduson belül nem módosÃthatók a kapott paraméterek:
static class Pelda
{
public static int Sum(ref readonly int a, ref readonly int b)
{
//fordÃtási hiba lenne:
//a = 22;
return a + b;
}
}