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 set
init
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 init
set
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 pro jednoduché deklarace 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 mplementované 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 , value
pro 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
, internal
protected
, , 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 vlastnostName
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 , Shape
a 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
*/