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 implementaci třídy je vlastnost jeden nebo dva bloky kódu představující přístupové get objekty nebo setinit přístupové objekty. Blok kódu pro přístup se get spustí při čtení vlastnosti. Blok kódu pro objekt set nebo init přístup se spustí při přiřazení vlastnosti k hodnotě. Vlastnost bez přístupového objektu set je považována za jen pro čtení. Vlastnost bez přístupového objektu get se považuje pouze za zápis. Vlastnost, která má oba přístupové objekty, je pro čtení i zápis. Pomocí přístupového objektu initset můžete místo přístupového objektu povolit nastavení vlastnosti jako součást inicializace objektů, ale jinak ji nastavit 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 pole, následované typem vlastnosti, následovaným názvem vlastnosti a následným blokem kódu, který deklaruje get-accessor a/nebo set příslušenství. 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 deklarován jako vlastnost, aby set přistupovací objekt mohl zajistit, Month aby Month hodnota byla 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 jednoduchých deklarací vlastností. Další informace naleznete v tématu Automaticky implementované vlastnosti.

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. Metodu virtuálního get přístupového objektu ale nelze vyčíst, protože kompilátor v době kompilace neví, která metoda se může ve skutečnosti volat 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
}

Když odkazujete na vlastnost s výjimkou cíle přiřazení, get je vyvolána přístupová položka ke čtení hodnoty vlastnosti. Příklad:

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

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

Přístupový get objekt musí být člen typu bod výrazu nebo musí končit příkazem return nebo throw a ovládací prvek nemůže odtékat z těla příslušenství.

Upozorňující

Je to špatný programovací styl změnit stav objektu pomocí přístupového objektu get .

Tento get přístup lze použít k vrácení hodnoty pole nebo k jeho výpočtu a 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.

Sada přístupového objektu

Přístupové set objekty se podobají 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 backingové pole. V následujícím příkladu set se do Name vlastnosti přidá přístupový objekt:

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

Při přiřazování hodnoty k vlastnosti, set je přístup vyvolán pomocí argumentu, který poskytuje novou hodnotu. 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 s tím rozdílem, že místo něj použijete init klíčové slovo set. Rozdíl je v tom, že init 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, internalprotected, , protected internal, nebo private protected. Tyto modifikátory přístupu definují, jak uživatelé třídy mají přístup k vlastnosti. Modifikátory get přístupu a set přístupové objekty pro stejnou vlastnost mohou mít různé modifikátory přístupu. Může být public například get povolit přístup jen pro čtení zvnějšku typu a set může být private nebo protected. Další informace naleznete v tématu Modifikátory accessu.

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 členy statické třídy.

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

Vlastnost přepsání virtuální vlastnosti lze také zapečetit a určit, ž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í virtuálního, abstraktního nebo přepsání modifikátoru u přístupového objektu 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: {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
*/

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
    
  • Přetypování (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, implementovat abstraktní třídu , Shapea přepsat jeho abstraktní Area vlastnost. Všimněte si použití modifikátoru přepsání u vlastností. Program přijme stranu jako vstup a vypočítá oblasti pro čtverec a datovou 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 = {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
*/

Viz také