Megosztás a következőn keresztül:


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á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.

C# 13-tól kezdődően mező alapú tulajdonságokat használhat az automatikusan implementált tulajdonság hozzáférőjének érvényesítésére, ahogy az alábbi példában látható:

public class DateExample
{
    public int Month
    {
        get;
        set
        {
            if ((value > 0) && (value < 13))
            {
                field = value;
            }
        }
    }
}

Fontos

A field kulcsszó egy előzetes verziójú funkció a C# 13-ban. Az <LangVersion> környezetfüggő kulcsszó használatához .NET 9-et kell használnia, és a projektfájljában az preview elemet field -re kell állítania.

Körültekintően használja a field kulcsszó funkciót egy olyan osztályban, amelynek van egy field nevű mezője. Az új field kulcsszó árnyékot ad egy tulajdonság-tartozék hatókörében elnevezett field mezőnek. A field változó nevét megváltoztathatja, vagy a @ token használatával hivatkozhat az field azonosítóra @field. További információkért olvassa el a kulcsszó funkciós specifikációjátfield.

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 egy virtuális, absztrakt vagy felülíró módosító használata egy statikus tulajdonság hozzáférő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 Name elrejti a tulajdonságot Name az alaposztályban. Ilyen esetben a módosító a new szá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
*/

Lásd még