Wprowadzenie do właściwości klas i metod dostępu
Właściwości klasy zapewniają elastyczny mechanizm odczytu, zapisu lub obliczania wartości pola danych. Są one wyświetlane jako elementy członkowskie danych publicznych, ale są one implementowane jako specjalne metody nazywane metody dostępu. Ta funkcja umożliwia obiektom wywołującym łatwe uzyskiwanie dostępu do danych i nadal pomaga promować bezpieczeństwo i elastyczność danych.
Korzystanie z właściwości
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 co uzyskiwanie dostępu do pola. Aby zaimplementować klasę, właściwość jest jednym lub dwoma blokami kodu reprezentującymi get metody dostępu i/lub set lub init akcesorium. Blok kodu dla metody dostępu get jest wykonywany, gdy właściwość jest odczytywana. Blok kodu dla set lub init akcesor jest wykonywany, gdy właściwość ma przypisaną wartość. Właściwość bez metody dostępu set jest uważana za tylko do odczytu. Właściwość bez metody dostępu get 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ć metody dostępu init zamiast metody dostępu set, 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 są często używane do obsługi następujących scenariuszy:
- 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 kodu definicji klasy. Właściwości są deklarowane przez określenie poziomu 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 akcesorium i/lub set akcesorium.
Akcesorium get
Treść metody get przypomina metodę . Musi zwrócić wartość typu właściwości. Kompilator języka C# i kompilator just in time (JIT) wykrywają typowe wzorce implementacji metody dostępu get i optymalizują te wzorce.
Na przykład metoda dostępu get zwracająca pole bez wykonywania żadnych obliczeń jest prawdopodobnie zoptymalizowana pod kątem odczytu pamięci tego pola. Automatycznie zaimplementowane właściwości, zbadane w następnej lekcji tego modułu, postępuj zgodnie z tym wzorcem i skorzystaj z tych optymalizacji. Nie można jednak utworzyć wbudowanej metody dostępu wirtualnej 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ę dostępu get zwracającą wartość pola prywatnego _name:
public class Employee
{
private string _name = "unknown"; // the name field
public string Name
{
get { return _name; } // the Name property
}
}
W tym przykładzie klasa Employee zawiera pole prywatne i właściwość publiczną. Oto wyjaśnienie definicji klasy Employee:
- Klasa
Employeejest definiowana za pomocą modyfikatora dostępu publicznego, co oznacza, że jest dostępny z dowolnego innego kodu w tym samym zestawie lub innym zestawie, który się do niego odwołuje. - Pole prywatne
_namejest deklarowane z typemstringi ma przypisaną wartość domyślną"unknown". - Właściwość publiczna
Namejest zadeklarowana z typemstring. Właściwość zawiera metodę dostępugetzwracającą wartość pola_name.
Nuta
Pola, które udostępniają wartości metod dostępu do właściwości, są często nazywane polami pomocniczymi .
Pośmiń minutę, aby rozważyć kod, który tworzy wystąpienie obiektu Employee i odczytuje wartość właściwości Name:
Employee employee = new Employee(); // create an instance of the Employee class
Console.Write(employee.Name); // use the get accessor to read the value of the Name property
Ten przykładowy kod tworzy wystąpienie nowego obiektu Employee o nazwie employee. Gdy kod odwołuje się do właściwości employee.Name, z wyjątkiem elementu docelowego przypisania, wywoływana jest get metodę dostępu w celu odczytania wartości właściwości. W tym przypadku metoda dostępu get zwraca wartość pola _name, które ma przypisaną wartość "unknown".
Blok kodu dla metody dostępu get może również służyć do zwracania wartości obliczeniowej. Może to być przydatne, gdy chcesz upewnić się, że właściwość zawsze zwraca wartość inną niż null. Na przykład:
public class Manager
{
private string? _name;
public string Name
{
get
{
return _name != null ? _name : "NA";
}
}
}
Akcesorium set
Metoda dostępu set 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 metody dostępu set lub init. Te typowe wzorce są zoptymalizowane, bezpośrednio zapisując pamięć dla pola zapasowego. W poniższym przykładzie metoda dostępu set jest dodawana do właściwości Name:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get
{
return _name != null ? _name : "NA";
}
set
{
_name = value;
}
}
}
Pośmiń chwilę, aby wziąć pod uwagę kod, który tworzy wystąpienie klasy Student. Po przypisaniu wartości do właściwości Name wywoływana jest set metodę dostępu przy użyciu argumentu, który udostępnia nową wartość. Na przykład:
var student = new Student();
student.Name = "StudentName"; // the set accessor is invoked here
Console.Write(student.Name); // the get accessor is invoked here
Akcesorium init
Kod do utworzenia metody dostępu init jest taki sam jak kod umożliwiający utworzenie metody dostępu set, z tą różnicą, że używasz słowa kluczowego init zamiast set. Różnica polega na tym, że akcesorium init może być używane tylko w konstruktorze lub za pomocą inicjatora obiektów.
Deklarowanie i używanie właściwości odczytu i zapisu
Właściwości zapewniają wygodę elementów członkowskich danych publicznych bez ryzyka, które są chronione, niekontrolowane i niezweryfikowane dostęp do danych obiektu. Właściwości deklarują metody dostępu: specjalne metody, które przypisują i pobierają wartości z bazowego elementu członkowskiego danych. Akcesorium set umożliwia przypisanie elementów członkowskich danych, a akcesorium get pobiera wartości składowych danych.
W tym przykładzie przedstawiono klasę Person, która ma dwie właściwości: Name (ciąg) i Age (int). Obie właściwości zapewniają get i set metody dostępu, dlatego są traktowane jako właściwości odczytu/zapisu.
class Person
{
private string _name = "N/A";
private int _age = 0;
// Declare a Name property of type string:
public string Name
{
get
{
return _name;
}
set
{
_name = value;
}
}
// Declare an Age property of type int:
public int Age
{
get
{
return _age;
}
set
{
_age = value;
}
}
}
class TestPerson
{
static void Main()
{
// Create a new Person object named person:
Person person = new Person();
// Print out the default name and age of the person:
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Set some values on the person object:
person.Name = "PersonName";
person.Age = 99;
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Increment the Age property:
person.Age += 1;
Console.WriteLine($"Person details - Name = {person.Name}, Age = {person.Age}");
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Person details - Name = N/A, Age = 0
Person details - Name = PersonName, Age = 99
Person details - Name = PersonName, Age = 100
*/
Składnia metody dostępu i techniki kodowania
Oprócz podstawowej składni deklarowania właściwości język C# zawiera składnię, która umożliwia pisanie bardziej zwięzłego i wyrazistego kodu. Te funkcje obejmują:
- Składowe wyrażeń
- Właściwości oparte na polach
- Wymagane właściwości
Składowe wyrażeń
Elementy członkowskie wyrażeń zapewniają bardziej zwięzłą składnię do pisania metod dostępu do właściwości jednowierszowych.
Nuta
Elementy członkowskie wyrażeń mogą być również stosowane do metod, indeksatorów i metod dostępu do zdarzeń.
Metody dostępu do właściwości często składają się z instrukcji jednowierszowych, które przypisują lub zwracają wynik wyrażenia. Dobrym przykładem jest klasa Person zbadana wcześniej w tej lekcji:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get
{
return _name != null ? _name : "NA";
}
set
{
_name = value;
}
}
}
W tym przykładzie właściwość Name używa instrukcji jednowierszowej, aby zwrócić wartość pola _name, jeśli nie ma wartości null, lub ciąg "NA", jeśli ma wartość null. Akcesorium set używa instrukcji jednowierszowej, aby przypisać wartość właściwości Name do pola _name.
Definicja treści wyrażenia składa się z tokenu =>, po którym następuje wyrażenie używane do przypisywania lub pobierania wartości właściwości. Ponieważ metody dostępu zdefiniowane dla klasy Student implementują instrukcję jednowierszową, dobrym kandydatem do aktualizacji przy użyciu definicji treści wyrażeń.
Poniższy fragment kodu aktualizuje klasę Student przy użyciu definicji treści wyrażeń dla get i set metod dostępu:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get => _name ?? "NA";
set => _name = value;
}
}
Właściwości kopii zapasowej pola
Począwszy od języka C# 13, można dodać walidację lub inną logikę w metodzie dostępu dla właściwości przy użyciu funkcji podglądu słowa kluczowego field. Słowo kluczowe field uzyskuje dostęp do syntetyzowanego pola kopii zapasowej kompilatora dla właściwości. Umożliwia pisanie metody dostępu do właściwości bez jawnego deklarowania oddzielnego pola zapasowego.
public class Person
{
public string? FirstName
{
get;
set => field = value.Trim();
}
// Omitted for brevity.
}
Ważny
Słowo kluczowe field to funkcja w wersji zapoznawczej w języku C# 13. Musisz użyć platformy .NET 9 i ustawić element <LangVersion> do wyświetlenia podglądu w pliku projektu, aby użyć field kontekstowego 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 słowo kluczowe field 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 pola jako @field.
Wymagane właściwości
Powyższy przykład umożliwia obiektowi wywołującym utworzenie Person przy użyciu konstruktora domyślnego bez ustawiania właściwości FirstName. Typ właściwości jest ustawiony na ciąg dopuszczalny do wartości null. Począwszy od języka C# 11, można wymagać od wywołujących ustawienia właściwości:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
// Omitted for brevity.
}
Powyższy kod wprowadza dwie zmiany w klasie Person. Najpierw deklaracja właściwości FirstName zawiera modyfikator required. Oznacza to, że każdy kod tworzący nowy Person musi ustawić tę właściwość przy użyciu inicjatora obiektu. Po drugie, konstruktor, który przyjmuje parametr firstName ma atrybut System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute. Ten atrybut informuje kompilator, że ten konstruktor ustawia wszystkie wymagane elementy członkowskie. Obiekty wywołujące używające tego konstruktora nie są wymagane do ustawiania właściwości required za pomocą inicjatora obiektu.
Ważny
Nie należy mylić required z wartością niepustą. Prawidłowe jest ustawienie właściwości required na wartość null lub default. Jeśli typ jest niemożliwy do wartości null, taki jak string w tych przykładach, kompilator wyświetla ostrzeżenie.
var aPerson = new Person("PersonName");
aPerson = new Person{ FirstName = "PersonName"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();