Używanie właściwości (Przewodnik programowania w języku C#)
Właściwości łączą aspekty pól i metod. Dla użytkownika obiektu właściwość wydaje się być polem; uzyskiwanie dostępu do właściwości wymaga tej samej składni. Aby zaimplementować klasę, właściwość jest jednym lub dwoma blokami kodu reprezentującymi metodę get
dostępu i/lub set
init
metodę dostępu. Blok kodu dla get
metody dostępu jest wykonywany, gdy właściwość jest odczytywana. Blok kodu dla set
metody lub init
jest wykonywany, gdy właściwość ma przypisaną wartość. Właściwość bez set
metody dostępu jest uważana za tylko do odczytu. Właściwość bez get
metody dostępu jest uważana za tylko do zapisu. Właściwość, która ma oba metody dostępu, to odczyt i zapis. Można użyć init
metody dostępu zamiast set
metody dostępu, aby umożliwić ustawienie właściwości w ramach inicjowania obiektu, ale w przeciwnym razie uczynić ją tylko do odczytu.
W przeciwieństwie do pól właściwości nie są klasyfikowane jako zmienne. W związku z tym nie można przekazać właściwości jako parametru ref
lub out
.
Właściwości mają wiele zastosowań:
- Mogą weryfikować dane przed zezwoleniem na zmianę.
- Mogą one w sposób niewidoczny uwidaczniać dane w klasie, w której te dane są pobierane z innego źródła, takiego jak baza danych.
- Mogą podjąć akcję, gdy dane zostaną zmienione, takie jak podniesienie zdarzenia lub zmiana wartości innych pól.
Właściwości są deklarowane w bloku klasy, określając poziom dostępu pola, a następnie typ właściwości, a następnie nazwę właściwości, a następnie blok kodu, który deklaruje get
-accessor i/lub set
akcesorium. Na przykład:
public class Date
{
private int _month = 7; // Backing store
public int Month
{
get => _month;
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}
W tym przykładzie parametr jest zadeklarowany jako właściwość, Month
dzięki czemu set
akcesorium może upewnić się, że Month
wartość jest ustawiona z zakresu od 1 do 12. Właściwość Month
używa pola prywatnego do śledzenia rzeczywistej wartości. Rzeczywista lokalizacja danych właściwości jest często określana jako "magazyn zapasowy" właściwości. Właściwości często używają pól prywatnych jako magazynu zapasowego. Pole jest oznaczone jako prywatne, aby upewnić się, że można je zmienić tylko przez wywołanie właściwości . Aby uzyskać więcej informacji na temat ograniczeń dostępu publicznego i prywatnego, zobacz Modyfikatory dostępu. Automatycznie zaimplementowane właściwości zapewniają uproszczoną składnię dla prostych deklaracji właściwości. Aby uzyskać więcej informacji, zobacz Automatycznie zaimplementowane właściwości.
Począwszy od języka C# 13, można użyć właściwości opartych na polach, aby dodać walidację do set
metody dostępu automatycznie zaimplementowanej właściwości, jak pokazano w poniższym przykładzie:
public class DateExample
{
public int Month
{
get;
set
{
if ((value > 0) && (value < 13))
{
field = value;
}
}
}
}
Ważne
Słowo field
kluczowe jest funkcją w wersji zapoznawczej w języku C# 13. Musisz użyć platformy .NET 9 i ustawić element <LangVersion>
na preview
w pliku projektu, aby użyć field
kontekstu słowa kluczowego.
Należy zachować ostrożność przy użyciu funkcji słowa kluczowego field
w klasie, która ma pole o nazwie field
. Nowe field
słowo kluczowe cieniuje pole o nazwie field
w zakresie metody dostępu właściwości. Możesz zmienić nazwę zmiennej field
lub użyć tokenu @
, aby odwołać się do identyfikatora field
jako @field
. Aby dowiedzieć się więcej, przeczytaj specyfikację funkcji słowa kluczowego field
.
Metodę pobierania
Treść get
metody dostępu przypomina metodę . Musi zwrócić wartość typu właściwości. Kompilator języka C# i kompilator just in time (JIT) wykrywają typowe wzorce implementowania get
metody dostępu i optymalizują te wzorce. Na przykład metoda dostępu zwracająca get
pole bez wykonywania żadnych obliczeń jest prawdopodobnie zoptymalizowana pod kątem odczytu pamięci tego pola. Automatycznie zaimplementowane właściwości są zgodne z tym wzorcem i korzystają z tych optymalizacji. Nie można jednak utworzyć wbudowanej metody dostępu wirtualnego get
, ponieważ kompilator nie wie w czasie kompilacji, która metoda może być rzeczywiście wywoływana w czasie wykonywania. W poniższym przykładzie przedstawiono metodę get
dostępu zwracającą wartość pola _name
prywatnego:
class Employee
{
private string _name; // the name field
public string Name => _name; // the Name property
}
W przypadku odwołowania się do właściwości, z wyjątkiem elementu docelowego przypisania, wywoływana jest metoda dostępu w get
celu odczytania wartości właściwości. Na przykład:
var employee= new Employee();
//...
System.Console.Write(employee.Name); // the get accessor is invoked here
Akcesorium get
musi być elementem członkowskim wyrażeń lub zakończyć w instrukcji return lub throw , a kontrolka nie może przepływać poza treść akcesorium.
Ostrzeżenie
Zazwyczaj jest to zły styl programowania, aby zmienić stan obiektu przy użyciu get
metody dostępu. Jednym wyjątkiem od tej reguły jest leniwa obliczona właściwość, w której wartość właściwości jest obliczana tylko wtedy, gdy jest ona najpierw dostępna.
Metodę get
dostępu można użyć do zwrócenia wartości pola lub obliczenia i zwrócenia jej. Na przykład:
class Manager
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
W poprzednim przykładzie, jeśli nie przypiszesz wartości do Name
właściwości, zwraca wartość NA
.
Akcesorium zestawu
Metoda set
dostępu przypomina metodę, której typ zwracany jest void. Używa niejawnego parametru o nazwie value
, którego typem jest typ właściwości. Kompilator i kompilator JIT rozpoznają również typowe wzorce dla elementu set
lub init
metody dostępu. Te typowe wzorce są zoptymalizowane, bezpośrednio zapisując pamięć dla pola zapasowego. W poniższym przykładzie set
metoda dostępu jest dodawana do Name
właściwości :
class Student
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
Po przypisaniu wartości do właściwości set
metodę dostępu jest wywoływana przy użyciu argumentu, który dostarcza nową wartość. Na przykład:
var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(student.Name); // the get accessor is invoked here
Jest to błąd podczas używania niejawnej nazwy parametru , value
dla deklaracji zmiennej lokalnej w metodzie set
dostępu.
Akcesor init
Kod do utworzenia init
metody dostępu jest taki sam jak kod w celu utworzenia metody dostępu, z tą różnicą set
, że używasz init
słowa kluczowego zamiast set
. Różnica polega na tym, że init
akcesorium może być używane tylko w konstruktorze lub za pomocą inicjatora obiektów.
Uwagi
Właściwości można oznaczyć jako public
, , private
, protected
internal
, , protected internal
lub private protected
. Te modyfikatory dostępu definiują sposób, w jaki użytkownicy klasy mogą uzyskiwać dostęp do właściwości. Metody get
i set
dla tej samej właściwości mogą mieć różne modyfikatory dostępu. Na przykład get
może to być public
zezwolenie na dostęp tylko do odczytu spoza typu, a set
może to być private
lub protected
. Aby uzyskać więcej informacji, zobacz Modyfikatory dostępu.
Właściwość można zadeklarować jako właściwość statyczną przy użyciu słowa kluczowego static
. Właściwości statyczne są dostępne dla obiektów wywołujących w dowolnym momencie, nawet jeśli żadne wystąpienie klasy nie istnieje. Aby uzyskać więcej informacji, zobacz Klasy statyczne i składowe klas statycznych.
Właściwość można oznaczyć jako właściwość wirtualną za pomocą słowa kluczowego wirtualnego. Właściwości wirtualne umożliwiają klasom pochodnym zastąpienie zachowania właściwości za pomocą słowa kluczowego zastąpienia . Aby uzyskać więcej informacji na temat tych opcji, zobacz Dziedziczenie.
Właściwość przesłaniająca właściwość wirtualną może być również zapieczętowana, określając, że dla klas pochodnych nie jest już wirtualna. Na koniec właściwość można zadeklarować jako abstrakcyjną. Właściwości abstrakcyjne nie definiują implementacji w klasie, a klasy pochodne muszą napisać własną implementację. Aby uzyskać więcej informacji na temat tych opcji, zobacz Klasy abstrakcyjne i zapieczętowane oraz składowe klasy.
Uwaga
Jest to błąd podczas używania modyfikatora wirtualnego, abstrakcyjnego lub zastępowania metody dostępu do właściwości statycznej.
Przykłady
W tym przykładzie przedstawiono właściwości wystąpienia, statyczne i tylko do odczytu. Akceptuje nazwę pracownika z klawiatury, zwiększa NumberOfEmployees
się o 1 i wyświetla nazwę i numer pracownika.
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:
}
Przykład ukrytej właściwości
W tym przykładzie pokazano, jak uzyskać dostęp do właściwości w klasie bazowej ukrytej przez inną właściwość o tej samej nazwie w klasie pochodnej:
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
*/
Poniżej przedstawiono ważne kwestie w poprzednim przykładzie:
- Właściwość
Name
w klasie pochodnej ukrywa właściwośćName
w klasie bazowej. W takim przypadkunew
modyfikator jest używany w deklaracji właściwości w klasie pochodnej:public new string Name
(Employee)
Rzutowanie służy do uzyskiwania dostępu do ukrytej właściwości w klasie bazowej:((Employee)m1).Name = "Mary";
Aby uzyskać więcej informacji na temat ukrywania członków, zobacz nowy modyfikator.
Przykład przesłonięcia właściwości
W tym przykładzie dwie klasy Cube
i Square
, implementują klasę abstrakcyjną, Shape
i przesłaniają jej właściwość abstrakcyjną Area
. Zwróć uwagę na użycie modyfikatora przesłonięcia we właściwościach. Program akceptuje stronę jako dane wejściowe i oblicza obszary dla kwadratu i modułu. Akceptuje również obszar jako dane wejściowe i oblicza odpowiednią stronę kwadratu i modułu.
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
*/