Sdílet prostřednictvím


Použití vlastností (Průvodce programováním v C#)

Vlastnosti kombinují aspekty polí i metod. Uživateli objektu se zdá, že vlastnost je pole; přístup k vlastnosti vyžaduje stejnou syntaxi. Pro implementátora třídy je vlastnost jeden nebo dva bloky kódu, které představují přístupovou metodu get a/nebo set či init přístupovou metodu. Blok kódu pro přístup se get spustí, když se vlastnost čte; blok kódu pro set nebo init přístup se spustí, když je vlastnosti přiřazena hodnota. Vlastnost bez přístupového objektu set je považována za jen pro čtení. Vlastnost bez přístupového prvku get se považuje za pouze zapisovatelnou. Vlastnost, která má oba přístupové metody, je čtení a zápis. Můžete použít přístupový objekt init místo přístupového objektu set, abyste umožnili nastavení vlastnosti jako součást inicializace objektu, ale jinak ji ponechali jen pro čtení.

Na rozdíl od polí nejsou vlastnosti klasifikovány jako proměnné. Proto nemůžete předat vlastnost jako ref nebo out parametr.

Vlastnosti mají mnoho použití:

  • Před povolením změny můžou ověřit data.
  • Mohou transparentně zveřejnit data ve třídě, kde se tato data načítají z jiného zdroje, například z databáze.
  • Můžou provést akci při změně dat, například při vyvolání události nebo změně hodnoty jiných polí.

Vlastnosti jsou deklarovány v bloku třídy zadáním úrovně přístupu vlastnosti, následované typem vlastnosti, následovaným názvem vlastnosti a následným blokem kódu, který deklaruje get-accessor a/nebo set-accessor. Příklad:

public class Date
{
    private int _month = 7;  // Backing store

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

V tomto příkladu je Month deklarován jako vlastnost, aby přístupový prvek set mohl zajistit, že hodnota Month bude nastavena mezi 1 a 12. Vlastnost Month používá soukromé pole ke sledování skutečné hodnoty. Skutečné umístění dat vlastnosti se často označuje jako "záložní úložiště". Vlastnosti běžně používají privátní pole jako záložní úložiště. Pole je označené jako soukromé, aby se zajistilo, že je možné ho změnit pouze voláním vlastnosti. Další informace o omezeních veřejného a privátního přístupu najdete v tématu Modifikátory přístupu. Automaticky implementované vlastnosti poskytují zjednodušenou syntaxi pro jednoduché deklarace vlastností. Další informace naleznete v tématu Automaticky implementované vlastnosti.

Počínaje jazykem C# 13 můžete pomocí vlastností založených na polích přidat ověřování k set přístupové objektu automaticky implementované vlastnosti, jak je znázorněno v následujícím příkladu:

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

Důležité

Klíčové slovo field je předváděcí funkce ve verzi C# 13. Musíte používat .NET 9 a nastavit prvek <LangVersion> na preview ve svém souboru projektu, abyste mohli použít kontextové klíčové slovo field.

Měli byste být opatrní při použití funkce klíčového slova field ve třídě, která má pole s názvem field. Nové field klíčové slovo stínuje pole pojmenované field v oboru přístupového objektu vlastnosti. Můžete změnit název field proměnné nebo pomocí @ tokenu odkazovat na field identifikátor jako @field. Další informace najdete ve specifikaci funkce pro field klíčové slovo.

Přístupový objekt get

Tělo get příslušenství se podobá tělu metody. Musí vrátit hodnotu typu vlastnosti. Kompilátor jazyka C# a kompilátor JIT (Just-in-Time) detekují běžné vzory pro implementaci přístupového objektu get a optimalizuje tyto vzory. Například přístupový get objekt, který vrací pole bez provedení výpočtu, je pravděpodobně optimalizován na čtení paměti daného pole. Automaticky implementované vlastnosti se řídí tímto vzorem a využívají tyto optimalizace. Nelze však vložit virtuální get přístupovou metodu, protože kompilátor neví během kompilace, která metoda může být skutečně zavolána za běhu. Následující příklad ukazuje přístupový objekt get , který vrací hodnotu soukromého pole _name:

class Employee
{
    private string _name;           // the name field
    public string Name => _name;    // the Name property
}

Při odkazování na vlastnost, s výjimkou, kdy je cílem přiřazení, je vyvolán přistupovač get ke čtení hodnoty vlastnosti. Příklad:

var employee = new Employee();
//...

System.Console.Write(employee.Name); // the get accessor is invoked here

Přístupový get prvek musí být členem s tělem tvořeným výrazem nebo končit příkazem return nebo throw a řízení nemůže opustit tělo přístupového prvku.

Varování

Obecně se jedná o špatný programovací styl, jak změnit stav objektu pomocí přístupového objektu get . Jednou z výjimek tohoto pravidla je opožděná vyhodnocená vlastnost, kde se hodnota vlastnosti vypočítá pouze při prvním přístupu.

Tento get přístupový prvek lze použít k vrácení hodnoty pole nebo k jejímu výpočtu a následnému vrácení. Příklad:

class Manager
{
    private string _name;
    public string Name => _name != null ? _name : "NA";
}

Pokud v předchozím příkladu nepřiřadíte hodnotu vlastnosti Name , vrátí hodnotu NA.

Metoda nastavování

Přístupový set objekt se podobá metodě, jejíž návratový typ je void. Používá implicitní parametr s názvem value, jehož typ je typ vlastnosti. Kompilátor a kompilátor JIT také rozpoznávají běžné vzory pro určitý set objekt nebo init příslušenství. Tyto běžné vzory jsou optimalizované, přímo zapisují paměť pro podpůrné pole. V následujícím příkladu je do vlastnosti set přidán přístupový prvek Name.

class Student
{
    private string _name;      // the name field
    public string Name         // the Name property
    {
        get => _name;
        set => _name = value;
    }
}

Přiřadíte-li hodnotu k vlastnosti, je pomocí argumentu, který poskytuje novou hodnotu, vyvolán přístupový objekt set. Příklad:

var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here

System.Console.Write(student.Name); // the get accessor is invoked here

Jedná se o chybu použití implicitního názvu parametru , valuepro deklaraci místní proměnné v přístupovém objektu set .

Inicializační příslušenství

Kód pro vytvoření přístupového objektu init je stejný jako kód pro vytvoření přístupového objektu set, pouze použijete klíčové slovo init místo set. Rozdíl je v tom, že přístupový objekt lze použít pouze v konstruktoru nebo pomocí inicializátoru objektu.

Poznámky

Vlastnosti mohou být označeny jako public, private, protectedinternal, , protected internal, nebo private protected. Tyto modifikátory přístupu definují, jak uživatelé třídy mají přístup k vlastnosti. Pro přístupové objekty get a set pro stejnou vlastnost mohou být použity různé modifikátory přístupu. Například get může být nastaven tak, aby umožňoval přístup jen pro čtení z vnějšku typu, a public může být set nebo private. Další informace naleznete v tématu Přístupové modifikátory.

Vlastnost lze deklarovat jako statickou vlastnost pomocí klíčového static slova. Statické vlastnosti jsou kdykoli k dispozici volajícím, i když žádná instance třídy neexistuje. Další informace naleznete v tématu Statické třídy a statičtí členové tříd.

Vlastnost lze označit jako virtuální vlastnost pomocí virtuálního klíčového slova. Virtuální vlastnosti umožňují odvozeným třídám přepsat chování vlastnosti pomocí klíčového slova override. Další informace o těchto možnostech naleznete v tématu Dědičnost.

Vlastnost přepisující virtuální vlastnost může být také zapečetěna, což specifikuje, že pro odvozené třídy již není virtuální. Nakonec lze deklarovat abstraktní vlastnost. Abstraktní vlastnosti nedefinují implementaci ve třídě a odvozené třídy musí zapsat vlastní implementaci. Další informace o těchto možnostech naleznete v tématu Abstraktní a zapečetěné třídy a členy třídy.

Poznámka:

Jedná se o chybu použití modifikátoru virtuálního, abstraktního nebo override u přístupové metody statické vlastnosti.

Příklady

Tento příklad ukazuje vlastnosti instance, statické a jen pro čtení. Přijme jméno zaměstnance z klávesnice, zvýší NumberOfEmployees o 1 a zobrazí jméno a číslo zaměstnance.

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říklad skryté vlastnosti

Tento příklad ukazuje, jak získat přístup k vlastnosti v základní třídě, která je skrytá jinou vlastností, která má stejný název v odvozené třídě:

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
*/

V předchozím příkladu jsou důležité následující body:

  • Vlastnost Name v odvozené třídě skryje vlastnost Name v základní třídě. V takovém případě new se modifikátor používá v deklaraci vlastnosti v odvozené třídě:
    public new string Name
    
  • Obsazení (Employee) se používá pro přístup ke skryté vlastnosti v základní třídě.
    ((Employee)m1).Name = "Mary";
    

Další informace o skrytí členů naleznete v novém modifikátoru.

Příklad přepsání vlastnosti

V tomto příkladu dvě třídy Cube a Square implementují abstraktní třídu Shape a přepisují její abstraktní vlastnost Area. Všimněte si použití modifikátoru override u vlastností. Program přijme stranu jako vstup a vypočítá plochy pro čtverec a krychli. Přijímá také oblast jako vstup a vypočítá odpovídající stranu čtverce a datové krychle.

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
*/

Viz také