Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
A tulajdonságok a mezők és a metódusok aspektusait egyesítik. Egy objektum felhasználója számára egy tulajdonság mezőnek tűnik; A tulajdonság eléréséhez ugyanaz a szintaxis szükséges. Az osztályt megvalósító programozó számára egy tulajdonság egy vagy két kódblokkot jelent, amelyek egy get lekérdezőt és/vagy egy set vagy init módosítót jelölnek. A get hozzáférő kódblokkját akkor hajtja végre a rendszer, amikor a tulajdonságot olvassák; a set vagy init hozzáférő kódblokkját akkor hajtják végre, amikor a tulajdonságnak értéket adnak. A hozzáférő nélküli set tulajdonságokat csak olvashatónak tekintjük. Hozzáférő nélküli get tulajdonságokat csak írhatónak tekintik. A mindkét hozzáférési metódust tartalmazó tulajdonság írható és olvasható. Hozzáférőt használhat a init helyett a set hozzáférővel, hogy engedélyezze a tulajdonság objektum inicializálásának részeként történő beállítását, de egyébként írásvédetté tegye azt.
A mezőkkel ellentétben a tulajdonságok nem tartoznak változók közé. Ezért nem adhat át tulajdonságot ref vagy out paraméterként.
A tulajdonságoknak számos felhasználási módja van:
- A módosítás engedélyezése előtt ellenőrizhetik az adatokat.
- Transzparensen elérhetővé tehetik az adatokat egy olyan osztályon, ahol az adatokat más forrásból, például egy adatbázisból kérik le.
- Az adatok módosításakor műveletet hajthatnak végre, például eseményt emelhetnek ki, vagy módosíthatják más mezők értékét.
A tulajdonságok az osztályblokkon belül deklarálhatók a mező hozzáférési szintjének megadásával, majd a tulajdonság típusával, a tulajdonság nevével, továbbá egy olyan kódblokkal, amely deklarál egy get-függvényhívót és/vagy egy set-függvényhívót. Példa:
public class Date
{
private int _month = 7; // Backing store
public int Month
{
get => _month;
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}
Ebben a példában tulajdonságként van deklarálva, Month így a set tartozék meggyőződhet arról, hogy az Month érték 1 és 12 között van beállítva. A Month tulajdonság egy privát mezőt használ a tényleges érték nyomon követéséhez. A tulajdonság adatainak valós helyét gyakran nevezik a tulajdonság "háttértárának". Gyakran előfordul, hogy a tulajdonságok háttértárként privát mezőket használnak. A mező privátként van megjelölve, így csak a tulajdonság meghívásával módosítható. A nyilvános és a privát hozzáférés korlátozásairól további információt az Access-módosítók című témakörben talál. Az automatikusan implementált tulajdonságok egyszerűsített szintaxist biztosítanak az egyszerű tulajdonságdeklarációkhoz. További információ: Automatikusan implementált tulajdonságok.
A C# 14-től mezővel támogatott tulajdonságok használatával érvényesítést adhat az automatikusan implementált tulajdonság set hozzáférőihez, ahogy az alábbi példában is látható:
public class DateExample
{
public int Month
{
get;
set
{
if ((value > 0) && (value < 13))
{
field = value;
}
}
}
}
A "get" hozzáférő
A tartozék teste get hasonlít egy módszerhez. A tulajdonságtípus értékét kell visszaadnia. A C# fordító és a just-in-time (JIT) fordító észleli a kiegészítő implementálásának gyakori mintáit, és optimalizálja ezeket a get mintákat. Például egy get hozzáférés, amely számítás nélkül ad vissza egy mezőt, valószínűleg az adott mező memóriaolvasására van optimalizálva. Az automatikusan implementált tulajdonságok ezt a mintát követik, és kihasználják ezeket az optimalizálásokat. A virtuális get kiegészítő metódusok azonban nem ágyazhatók be, mert a fordító nem tudja a fordításkor, hogy melyik metódus hívható meg futásidőben. Az alábbi példa egy olyan kiegészítőt get mutat be, amely egy magánmező _nameértékét adja vissza:
class Employee
{
private string _name; // the name field
public string Name => _name; // the Name property
}
Ha a tulajdonságra hivatkozik, kivéve a hozzárendelés célját, a rendszer meghívja a get tartozékot a tulajdonság értékének olvasásához. Példa:
var employee = new Employee();
//...
System.Console.Write(employee.Name); // the get accessor is invoked here
A get hozzáférésnek kifejezési testű tagnak kell lennie, vagy visszatérési vagy dobási utasítással kell végződnie, és a vezérlés nem léphet ki a hozzáférés törzséből.
Figyelmeztetés
Általában rossz programozási stílus az objektum állapotának módosítása a get tartozék használatával. A szabály alól kivételt képeznek a lusta kiértékelt tulajdonságok, ahol egy tulajdonság értékét csak az első hozzáféréskor számítja ki a rendszer.
A get tartozék használható a mező értékének visszaadására vagy kiszámítására és visszaadására. Példa:
class Manager
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
Az előző példában, ha nem rendel hozzá értéket a Name tulajdonsághoz, az az értéket NAadja vissza.
A készlet tartozéka
A set lekérdező hasonlít egy olyan metódusra, amelynek visszatérési típusa void. Implicit paramétert valuehasznál, amelynek típusa a tulajdonság típusa. A fordító és a JIT-fordító is felismerik a set vagy init lekérdező gyakori mintáit. Ezeket a gyakori mintákat optimalizálták, közvetlenül a háttérmező memóriáját írva. Az alábbi példában egy set kiegészítőt adunk hozzá a Name tulajdonsághoz:
class Student
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
Amikor értéket rendel a tulajdonsághoz, a rendszer meghívja a set kiegészítőt egy argumentum használatával, amely az új értéket adja meg. Példa:
var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(student.Name); // the get accessor is invoked here
Hiba az implicit paraméternév valuehasználata egy helyi változódeklarációhoz egy set tartozékban.
Az init tartozék
A init kiszolgáló létrehozásához használt kód ugyanaz, mint a set kiszolgáló létrehozásához használt, azzal a különbséggel, hogy a init kulcsszót használja a set helyett. A különbség az, hogy a init tartozék csak a konstruktorban vagy egy objektum-inicializáló használatával használható.
Megjegyzések
A tulajdonságok megjelölhetők public, private, protected, internalprotected internalvagy private protected. Ezek a hozzáférési módosítók határozzák meg, hogy az osztály felhasználói hogyan férhetnek hozzá a tulajdonsághoz. Az ugyanahhoz a tulajdonsághoz tartozó get és set lekérdezők különböző hozzáférési módosítókkal rendelkezhetnek. Például a get lehet public, hogy kívülről csak olvasási hozzáférést engedélyezzen a típushoz, és a set lehet private vagy protected. További információ: Access Modifiers.
A tulajdonság a kulcsszó használatával static deklarálható statikus tulajdonságként. A statikus tulajdonságok bármikor elérhetők a hívók számára, még akkor is, ha az osztálynak nincs példánya. További információ: Statikus osztályok és statikus osztálytagok.
A tulajdonság a virtuális kulcsszóval jelölhető meg virtuális tulajdonságként. A virtuális tulajdonságok lehetővé teszik a származtatott osztályok számára, hogy felülbírálják a tulajdonság viselkedését a override kulcsszó használatával. További információ ezekről a lehetőségekről: Öröklés.
A virtuális tulajdonságot felülíró tulajdonság is lezárható, megadva, hogy származtatott osztályok esetén már nem virtuális. Végül egy tulajdonság absztraktként is deklarálható. Az absztrakt tulajdonságok nem definiálnak implementációt az osztályban, a származtatott osztályoknak pedig saját implementációt kell írniuk. További információ ezekről a lehetőségekről: Absztrakt és lezárt osztályok és osztálytagok.
Feljegyzés
Hiba, ha egy virtuális, absztrakt vagy felülbírálási módosítót használunk egy statikus tulajdonság hozzáférőjén.
Példák
Ez a példa a példány, a statikus és az írásvédett tulajdonságokat mutatja be. Elfogadja az Alkalmazott nevét a billentyűzetről, NumberOfEmployees értékét 1-gyel növeli, és megjeleníti az Alkalmazott nevét és számát.
public class Employee
{
public static int NumberOfEmployees;
private static int _counter;
private string _name;
// A read-write instance property:
public string Name
{
get => _name;
set => _name = value;
}
// A read-only static property:
public static int Counter => _counter;
// A Constructor:
public Employee() => _counter = ++NumberOfEmployees; // Calculate the employee's number:
}
Példa rejtett tulajdonságra
Ez a példa bemutatja, hogyan érhet el egy olyan tulajdonságot egy alaposztályban, amelyet egy másik, azonos nevű tulajdonság rejt el egy származtatott osztályban:
public class Employee
{
private string _name;
public string Name
{
get => _name;
set => _name = value;
}
}
public class Manager : Employee
{
private string _name;
// Notice the use of the new modifier:
public new string Name
{
get => _name;
set => _name = value + ", Manager";
}
}
class TestHiding
{
public static void Test()
{
Manager m1 = new Manager();
// Derived class property.
m1.Name = "John";
// Base class property.
((Employee)m1).Name = "Mary";
System.Console.WriteLine($"Name in the derived class is: {m1.Name}");
System.Console.WriteLine($"Name in the base class is: {((Employee)m1).Name}");
}
}
/* Output:
Name in the derived class is: John, Manager
Name in the base class is: Mary
*/
Az előző példában a következő fontos pontok szerepelnek:
- A származtatott osztály tulajdonsága
Nameelrejti a tulajdonságotNameaz alaposztályban. Ilyen esetben a módosító anewszármaztatott osztályban lévő tulajdonság deklarációjában használatos:public new string Name - A típuskonvertálás
(Employee)az alaposztály rejtett tulajdonságának elérésére szolgál:((Employee)m1).Name = "Mary";
A tagok elrejtésével kapcsolatos további információkért tekintse meg az új módosítót.
Példa a tulajdonság felülbírálására
Ebben a példában két osztály, Cube és Square, implementál egy absztrakt osztályt, Shape, és felülbírálja annak absztrakt Area tulajdonságát. Figyelje meg a felülbírálás módosítójának használatát a tulajdonságokon. A program bemenetként elfogadja az oldalt, és kiszámítja a négyzet és a kocka területeit. Bemenetként is elfogadja a területet, és kiszámítja a négyzet és a kocka megfelelő oldalát.
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
//constructor
public Square(double s) => side = s;
public override double Area
{
get => side * side;
set => side = System.Math.Sqrt(value);
}
}
class Cube : Shape
{
public double side;
//constructor
public Cube(double s) => side = s;
public override double Area
{
get => 6 * side * side;
set => side = System.Math.Sqrt(value / 6);
}
}
class TestShapes
{
static void Main()
{
// Input the side:
System.Console.Write("Enter the side: ");
double side = double.Parse(System.Console.ReadLine());
// Compute the areas:
Square s = new Square(side);
Cube c = new Cube(side);
// Display the results:
System.Console.WriteLine($"Area of the square = {s.Area:F2}");
System.Console.WriteLine($"Area of the cube = {c.Area:F2}");
System.Console.WriteLine();
// Input the area:
System.Console.Write("Enter the area: ");
double area = double.Parse(System.Console.ReadLine());
// Compute the sides:
s.Area = area;
c.Area = area;
// Display the results:
System.Console.WriteLine($"Side of the square = {s.side:F2}");
System.Console.WriteLine($"Side of the cube = {c.side:F2}");
}
}
/* Example Output:
Enter the side: 4
Area of the square = 16.00
Area of the cube = 96.00
Enter the area: 24
Side of the square = 4.90
Side of the cube = 2.00
*/