Tulajdonságok használata (C# programozási útmutató)
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ály megvalósítójának egy tulajdonság egy vagy két kódblokk, amely egy get
tartozékot és/vagy tartozékot set
init
jelöl. A tartozék kódblokkját a get
rendszer a tulajdonság beolvasásakor hajtja végre; a kódblokk set
a init
tulajdonság értékhez való hozzárendelésekor lesz végrehajtva. A tartozék nélküli set
tulajdonságok írásvédettnek minősülnek. A tartozék nélküli get
tulajdonságok írásvédettnek minősülnek. A mindkét tartozékot tartalmazó tulajdonság írás-olvasás. Tartozék helyett set
kiegészítővel init
engedélyezheti, hogy a tulajdonság az objektum inicializálásának részeként legyen beállítva, de máskülönben írásvédetté teheti.
A mezőkkel ellentétben a tulajdonságok nem tartoznak változók közé. Ezért nem adhat át tulajdonságot paraméterként vagy out
paraméterkéntref
.
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ályblokkban deklarálhatók a mező hozzáférési szintjének megadásával, majd a tulajdonság típusával, majd a tulajdonság nevével, majd egy kódblokkgal, amely -accessort és/vagy tartozékot set
deklarálget
. 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 lekéréses tartozék
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
olyan tartozék, amely számítás nélkül ad vissza egy mezőt, valószínűleg az adott mező memóriájába van optimalizálva. Az automatikusan mplemented tulajdonságok követik ezt a mintát, é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
tartozéknak kifejezési testű tagnak kell lennie, vagy visszatérési vagy dobási utasítással kell végződnie, és a vezérlő nem tud áramlani a tartozék törzsén.
Figyelmeztetés
Rossz programozási stílus az objektum állapotának módosítása a get
tartozék használatával.
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 NA
adja vissza.
A készlet tartozéka
A set
tartozék hasonlít egy olyan metódusra, amelynek visszatérési típusa érvénytelen. Implicit paramétert value
használ, amelynek típusa a tulajdonság típusa. A fordító és a JIT-fordító is felismeri egy vagy init
több tartozék gyakori mintáitset
. Ezek a gyakori minták optimalizálva vannak, közvetlenül a háttérmező memóriájának megírásával. 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 value
használata egy helyi változódeklarációhoz egy set
tartozékban.
Az init tartozék
A kiegészítő létrehozásához init
használt kód megegyezik a kiegészítő létrehozásához használt set
kóddal, azzal a kivételével, hogy a kulcsszót használja ahelyettset
, hogy a init
. 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
, internal
protected internal
vagy 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. Ugyanahhoz get
a tulajdonsághoz és set
tartozékaihoz különböző hozzáférési módosítók tartozhatnak. Lehetséges például, get
public
hogy a típuson kívülről engedélyezi az írásvédett hozzáférést, és az 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 felülbírálási 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 virtuális, absztrakt vagy felülbírálási módosító használata statikus tulajdonság tartozékán.
Példák
Ez a példa a példányok, a statikus és az írásvédett tulajdonságokat mutatja be. Elfogadja az alkalmazott nevét a billentyűzetről, 1-zel növekszik NumberOfEmployees
, é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: {0}", m1.Name);
System.Console.WriteLine("Name in the base class is: {0}", ((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
Name
elrejti a tulajdonságotName
az alaposztályban. Ilyen esetben a módosító anew
származtatott osztályban lévő tulajdonság deklarációjában használatos:public new string Name
- A bedobá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 és Cube
Square
egy absztrakt osztály implementálása, Shape
valamint az absztrakt Area
tulajdonság felülbírálása. 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 = {0:F2}", s.Area);
System.Console.WriteLine("Area of the cube = {0:F2}", c.Area);
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 = {0:F2}", s.side);
System.Console.WriteLine("Side of the cube = {0:F2}", c.side);
}
}
/* 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
*/