Použití vlastností (Průvodce programováním v C#)
Vlastnosti kombinují aspekty polí i metod. Pro uživatele objektu se vlastnost jeví jako pole. Přístup k vlastnosti vyžaduje stejnou syntaxi. Pro implementátor třídy je vlastnost jeden nebo dva bloky kódu, které představují přístupový objekt get nebo přístupový objekt set. Blok kódu přístupového objektu se spustí při čtení vlastnosti. Blok kódu pro přístupový objekt se spustí, když je vlastnosti get set přiřazena nová hodnota. Vlastnost bez set přístupového objektu se považuje za jen pro čtení. Vlastnost bez get přístupového objektu se považuje za jen pro zápis. Vlastnost, která má oba přístupové objekty, je pro čtení i zápis. V jazyce C# 9 a novějších můžete použít přístupový objekt místo přístupového objektu a nastavit vlastnost init set jen pro čtení.
Na rozdíl od polí nejsou vlastnosti klasifikovány jako proměnné. Proto nelze předat vlastnost jako parametr ref nebo out.
Vlastnosti mají mnoho využití: před povolením změny mohou ověřovat data. Mohou transparentně zveřejnit data ve třídě, kde se tato data skutečně načítá z nějakého jiného zdroje, jako je databáze. Mohou provést akci při změně dat, jako je například vyvolání události nebo změna hodnoty jiných polí.
Vlastnosti jsou deklarovány v bloku třídy zadáním úrovně přístupu pole, za nímž následuje typ vlastnosti, za nímž následuje název vlastnosti a za ním blok kódu, který deklaruje přistupující objekt get nebo přistupující set objekt. Napří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ána jako vlastnost, aby přistupovací objekt mohl zajistit, aby byla hodnota nastavena Month mezi 1 a set Month 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álohovací úložiště" vlastnosti. Je běžné, že vlastnosti používají privátní pole jako zálohovací úložiště. Pole je označeno jako soukromé, aby bylo 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 najdete v tématu Automaticky implementované vlastnosti.
Přístupový objekt get
Tělo get přístupového objektu se podobá textu metody . Musí vracet hodnotu typu vlastnosti. Spuštění get přístupového objekt je ekvivalentní ke čtení hodnoty pole. Pokud například vracíte privátní proměnnou z přístupového objektu a optimalizace jsou povoleny, kompilátor vloží volání metody přistupující objekt, takže negeneruje žádnou režii volání get get metody. Nelze však inlinovat metodu virtuálního přístupového objekt, protože kompilátor v době kompilace neví, která metoda může být skutečně get volána za běhu. Následuje get přístupový objekt, který vrací hodnotu privátního pole _name :
class Person
{
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í, vyvolá se přistupovací objekt pro čtení get hodnoty vlastnosti. Například:
Person person = new Person();
//...
System.Console.Write(person.Name); // the get accessor is invoked here
Přístupový get objekt musí končít příkazem return nebo throw a řízení nemůže proudit mimo tělo přístupového objektu.
Změna stavu objektu pomocí přístupového objektu je špatným get programovacím stylem. Například následující přistupující objekt má vedlejší účinek změny stavu objektu při každém přístupu _number k poli.
private int _number;
public int Number => _number++; // Don't do this
Přístupový get objekt lze použít k vrácení hodnoty pole nebo k výpočtu a vrácení hodnoty. Například:
class Employee
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
Pokud v předchozím segmentu kódu nepřiřadíte hodnotu vlastnosti , vrátí Name hodnotu NA .
Přístupový objekt set
Přístupový set objekt se podobá metodě, jejíž návratový typ je void. Používá implicitní parametr s názvem value , jehož typ je typem vlastnosti . V následujícím příkladu se set do vlastnosti přidá přistupovací Name objekt:
class Person
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
Když přiřadíte hodnotu vlastnosti , vyvolá se přistupovací objekt pomocí set argumentu, který poskytuje novou hodnotu. Například:
Person person = new Person();
person.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(person.Name); // the get accessor is invoked here
Při použití implicitního názvu parametru pro deklaraci místní proměnné v přistupování se jedná value o set chybu.
Initimativní přístupový objekt
Kód pro vytvoření přistupující objekt je stejný jako kód pro vytvoření přistupující objekt s tím rozdílem, že místo použijete init set klíčové slovo init set . Rozdíl je v tom, že přístupový objekt lze použít pouze v konstruktoru init nebo pomocí inicializátoru objektu.
Poznámky
Vlastnosti je možné označit jako public , , , , nebo private protected internal protected internal private protected . Tyto modifikátory přístupu definují, jak mohou uživatelé třídy přistupovat k vlastnosti . Přístupové objekty a get pro stejnou vlastnost mohou mít různé set modifikátory přístupu. Například může být povolit přístup jen pro čtení z vnějšku typu a get public může být nebo set private protected . Další informace najdete v tématu Modifikátory přístupu.
Vlastnost může být deklarována jako statická vlastnost pomocí klíčového static slova . Díky tomu je vlastnost k dispozici volajícím kdykoli, i když neexistuje žádná instance třídy. Další informace najdete v tématu Statické třídy a Členy statických tříd.
Vlastnost může být označena jako virtuální vlastnost pomocí klíčového slova virtual. To umožňuje odvozeným třídám přepsat chování vlastnosti pomocí klíčového slova override. Další informace o těchto možnostech najdete v tématu Dědičnost.
Vlastnost přepisující virtuální vlastnost může být také zapečetěnáa určuje, že pro odvozené třídy už není virtuální. A konečně, vlastnost může být deklarována jako abstraktní. To znamená, že ve třídě není žádná implementace a odvozené třídy musí psát vlastní implementaci. Další informace o těchto možnostech najdete v tématu Abstraktní a zapečetěné třídy a členy třídy.
Poznámka
Jedná se o chybu při použití virtuálního , abstraktníhonebo přepisového modifikátoru u přístupového objektu statické vlastnosti.
Příklady
Tento příklad ukazuje vlastnosti instance, statické vlastnosti a vlastnosti jen pro čtení. Přijme jméno zaměstnance z klávesnice, zvýší se o 1 a zobrazí jméno a NumberOfEmployees čí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:
}
class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";
System.Console.WriteLine("Employee number: {0}", Employee.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
/* Output:
Employee number: 108
Employee name: Claude Vige
*/
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
{
static void Main()
{
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é body:
Vlastnost
Namev odvozené třídě skryje vlastnostNamev základní třídě. V takovém případě senewmodifikátor používá v deklaraci vlastnosti v odvozené třídě:public new string Name(Employee)Přetypování se používá pro přístup ke skryté vlastnosti v základní třídě:((Employee)m1).Name = "Mary";Další informace o skrytí členů najdete v novém modifikátoru.
Příklad přepsání vlastnosti
V tomto příkladu dvě třídy a Cube Square implementují abstraktní třídu Shape a přepíší její abstraktní Area vlastnost. Všimněte si použití modifikátoru přepsání u vlastností. Program jako vstup přijímá stranu a vypočítá oblasti pro čtverec a datovou krychli. Přijímá také oblast jako vstup a vypočítá odpovídající stranu pro čtverec a datovou krychli.
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
*/