Folytassuk továbbra is a példát a LivingObject
és a Damager
közt, amit az előző leckékben elemeztünk:
A LivingObject
-nek volt egy private
field-je health
néven. Azt mondtuk, hogy ezt a field-et nem szeretnénk, hogy bárki szabadon módosítsa. Csakis a publikus TakeDamage
metódus segítségével volt lehetséges osztályon kívülről a health
értékének meg változtatása.
Getter és Setter metódusok
A fenti példát tovább szőve, mi van akkor, ha valaki csak le szeretné kérdezni a health
érétkét. Erre könnyen lehet hogy szükség van, de mióta a field privát, nincs lehetőség rá.
Írhatunk viszont egy lekérdező, azaz getter metódust a LivingObject
-be csak arra a célra, hogy megkapjuk ezt az információk:
class LivingObject
{
float health; // Privát field
public float GetHealth() // Publikus lekérdező metódus
{
return health;
}
... // Többi kód
}
Használata:
LivingObject livingObj = new LivingObject(100, Element.Fire, 0.75f);
float health = livingObj.GetHealth();
Tegyük fel, hogy azt is meg szeretnénk gátolni, hogy a Damager
osztálynak bárki beállítson egy negatív sebzés értéket, vagy olyat, ami nagyobb, mint 100. Ezt csak úgy tudjuk elérni, hogy private
láthatóságot adunk a damage
field-nek.
Ezúttal azt szeretnénk, hogy lehessen módosítani is az értékét, de bizonyos korlátok közt. Tehát nem csak egy lekérdező azaz getter, hanem egy beállító azaz setter is szükséges.
class Damager // Sebző osztály
{
float damage; // Privát field
public float GetDamage() // Publikus lekérdező metódus
{
return damage;
}
public SetDamage(float newValue) // Publikus beállító metódus
{
if(newValue < 0)
damage = 0;
else if(newValue > 100)
damage = 100;
else
damage = newValue;
// Ugyanez rövidebben:
damage = Math.Clamp(newValue, 0, 100);
}
}
A fenti kód ugyan tökéletesn működőképes megoldás az osztályon kívülről használva nem a legszebb:
// Régi módja a damage elérésének:
float oldDamage = damager.damage;
float newDamage = -55.5f;
damager.damage = newDamage;
// Új módja a damage elérésének:
float oldDamage = damager.GetDamage();
float newDamage = -55.5f;
damager.SetDamage(newDamage);
Property
A property vagy magyarul tulajdonság egy olyan tagja egy összetett típusnak, ami valahol félúton van a field és a metódus közt: Úgy használható, mint egy változó, de úgy viselkedik mint egy metódus (vagy kettő).
Segítségével elérhető, hogy olyan szabályozottan férjünk hozzá egy változóhoz, ahogyan azt tettük getter és setter metódusokkal, de kívülről mégis olyan egyszerű és átlátható használni őket mint egy változót.
class Damager // Sebző osztály
{
float damage; // Privát field
public float Damage // Publikus protperty
{
get { return damage; } // getter
set { damage = Math.Clamp(value, 0, 100); } // setter
}
}
// Használata osztályon kívülről
float oldDamage = damager.Damage;
float newDamage = -55.5f;
damager.Damage = newDamage;
Ha egy soros a getter vagy a setter akkor kapcsos zárójelek helyett használható az =>
operátor így:
public float Damage // Publikus protperty
{
get => damage; // getter
set => damage = Math.Clamp(value, 0, 100); // setter
}
Protperty-k esetén lehet külön lehet szabályozni a getter és a setter láthatóságát.
public float Damage // Publikus protperty
{
get => damage; // publikus getter
private set => damage = Math.Clamp(value, 0, 100); // private setter
}
// Ebben az esetben a setter csak osztályon belül használható.
Auto-Implemented Property
Ha a property-k, nem rendelkeznek egyedi logikával, és csak egy privát field elérését biztosítják akkor használható egy még egyszerűbb felírása a field és property párosnak:
public float Damage { get; set; } // AutoProperty
Ezt Auto-Implemented Property-nek vagy röviden AutoProperty-nek nevezzük.
Ugyanez így nézni ki Auto-Implemented Property nélkül:
float damage; // Privát field
public float Damage // Publikus protperty
{
get => damage; // getter
set => damage = damage; // setter
}
// Ezt a kódot AutoProperty esetén a fordító a háttérben létrehozza nekünk.
Az auto property-k használatával leegyszerűsíthetjük a kódunkat, mivel nem kell megadnunk külön get
és set
blokkokat.
Felmerülhet a kérdés, miért hasznos egyáltalán egy Auto Property ahelyett, hogy egyszerűen csak egy szimpla field-et használnánk a célra.
Az egyik előnye az AutoPropert-nek a szimpla field-el szemben, hogy egyedileg szbaályozható a getter és a szetter láthatósága. Példa:
public float Damage { get; private set; } // AutoProperty
(A másik előnye az AutoPropert-nek, hogy lehet egy interfész része property, de field nem. Ám az interfészekről nem tanulunk ezen a kurzuson.)