Komme i gang med klasseegenskaper og -tilgangsmenn
Klasseegenskaper gir en fleksibel mekanisme for å lese, skrive eller beregne verdien for et datafelt. De vises som offentlige datamedlemmer, men de implementeres som spesielle metoder som kalles -tilgangsmenn. Denne funksjonen gjør det enkelt for innringere å få tilgang til data og bidrar likevel til å fremme datasikkerhet og fleksibilitet.
Bruke egenskaper
Egenskaper kombinerer aspekter av både felt og metoder. For brukeren av et objekt ser en egenskap ut til å være et felt. Tilgang til egenskapen krever samme syntaks som tilgang til et felt. For implementereren av en klasse er en egenskap én eller to kodeblokker, som representerer en get-tilgangsør og/eller en set eller en init tiltreder. Kodeblokken for get-tilgangsøren kjøres når egenskapen leses. Kodeblokken for set eller init accessor kjøres når egenskapen tilordnes en verdi. En egenskap uten en set accessor regnes som skrivebeskyttet. En egenskap uten en get accessor regnes som skrivebeskyttet. En egenskap som har begge tilgangsmennene, er skrivebeskyttet. Du kan bruke en init accessor i stedet for en set accessor for å aktivere egenskapen som en del av objekt initialisering, men ellers gjøre den skrivebeskyttet.
I motsetning til felt klassifiseres ikke egenskaper som variabler. Derfor kan du ikke sende en egenskap som en ref- eller out-parameter.
Egenskaper brukes ofte til å støtte følgende scenarioer:
- De kan validere data før de tillater en endring.
- De kan gjennomsiktig vise data i en klasse der dataene hentes fra en annen kilde, for eksempel en database.
- De kan utføre en handling når data endres, for eksempel å heve en hendelse eller endre verdien for andre felt.
Egenskaper deklareres i kodeblokken for en klassedefinisjon. Egenskaper deklareres ved å angi tilgangsnivået for feltet, etterfulgt av egenskapstypen, etterfulgt av navnet på egenskapen, etterfulgt av en kodeblokk som deklarerer en get accessor og/eller en set accessor.
Den get tiltrederen
Brødteksten til get accessor ligner på en metode. Den må returnere en verdi for egenskapstypen. Kompilatoren C# og Just-in-time (JIT) oppdager vanlige mønstre for implementering av get accessor, og optimaliserer for disse mønstrene.
En get som for eksempel returnerer et felt uten å utføre noen beregning, er sannsynligvis optimalisert til en minnelesning av feltet. Implementerte egenskaper automatisk, undersøkt i neste enhet i denne modulen, følger dette mønsteret og drar nytte av disse optimaliseringene. En virtuell get accessor-metode kan imidlertid ikke være inlined fordi kompilatoren ikke vet på kompileringstidspunktet hvilken metode som faktisk kan kalles ved kjøretid.
Eksemplet nedenfor viser en get som returnerer verdien for et privat felt _name:
public class Employee
{
private string _name = "unknown"; // the name field
public string Name
{
get { return _name; } // the Name property
}
}
I dette eksemplet inneholder Employee-klassen et privat felt og en offentlig egenskap. Her er en forklaring av Employee klassedefinisjonen:
- Klassen
Employeeer definert med endring av offentlig tilgang, noe som betyr at den er tilgjengelig fra en annen kode i samme samling eller en annen samling som refererer til den. - Det private feltet
_namedeklareres medstringtype og tilordnes en standardverdi,"unknown". - Den offentlige
Nameer deklarert med denstringtypen. Egenskapen inneholder engetsom returnerer verdien for_name-feltet.
Notat
Feltene som inneholder verdiene for egenskapstilgangstakere, kalles ofte støttefelt.
Ta deg tid til å vurdere koden som startet et Employee objekt, og leser verdien for Name-egenskapen:
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
Dette kodeeksempelet skiller et nytt Employee objekt med navnet employee. Når koden refererer til employee.Name-egenskapen, bortsett fra som mål for en tildeling, aktiveres get til å lese verdien for egenskapen. I dette tilfellet returnerer get accessor verdien til _name-feltet, som er tilordnet verdien "unknown".
Kodeblokken for en get accessor kan også brukes til å returnere en beregnet verdi. Dette kan være nyttig når du vil sikre at en egenskap alltid returnerer en verdi som ikke er null. For eksempel:
public class Manager
{
private string? _name;
public string Name
{
get
{
return _name != null ? _name : "NA";
}
}
}
Den set tiltrederen
Den set accessor ligner på en metode der returtypen er ugyldig. Den bruker en implisitt parameter kalt value, hvis type er typen egenskap. Kompilatoren og JIT-kompilatoren gjenkjenner også vanlige mønstre for en set eller init accessor. Disse vanlige mønstrene er optimalisert, og skriver direkte inn minnet for støttefeltet. I eksemplet nedenfor legges en set til i Name-egenskapen:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get
{
return _name != null ? _name : "NA";
}
set
{
_name = value;
}
}
}
Ta deg tid til å vurdere koden som oppretter en forekomst av Student-klassen. Når du tilordner en verdi til Name-egenskapen, aktiveres set accessor ved hjelp av et argument som gir den nye verdien. For eksempel:
var student = new Student();
student.Name = "StudentName"; // the set accessor is invoked here
Console.Write(student.Name); // the get accessor is invoked here
Den init tiltrederen
Koden for å opprette en init accessor er den samme som koden for å opprette en set-tilgangsperson, bortsett fra at du bruker nøkkelordet init i stedet for set. Forskjellen er at init-tilgangsøren bare kan brukes i konstruktøren eller ved hjelp av en objektinitialiserer.
Deklarer og bruk lese-skriveegenskaper
Egenskaper gjør det enkelt for medlemmer av offentlige data uten risikoer som kommer med ubeskyttet, ukontrollert og ubekreftet tilgang til et objekts data. Egenskaper erklærer accessors: spesielle metoder som tilordner og henter verdier fra det underliggende datamedlemmet. Accessoren set gjør det mulig å tilordne datamedlemmer, og get-tilgangsøren henter datamedlemsverdier.
Dette eksemplet viser en Person klasse som har to egenskaper: Name (streng) og Age (int). Begge egenskapene gir get- og set-tilgangstakere, slik at de anses som lese-/skriveegenskaper.
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
*/
Accessor-syntaks og kodingsteknikker
I tillegg til den grunnleggende syntaksen for deklarering av egenskaper, inkluderer C# syntaks som gjør det mulig å skrive mer konsis og uttrykksfull kode. Disse funksjonene inkluderer:
- Uttrykksbebodde medlemmer
- Feltstøttede egenskaper
- Obligatoriske egenskaper
Uttrykksbebodde medlemmer
Uttrykksbebodde medlemmer gir en mer konsis syntaks for skriving av egenskapstilgangstakere med én linje.
Notat
Uttrykksbeskjærte medlemmer kan også brukes på metoder, indekserere og hendelsestilgangstakere.
Egenskapstilgangstakere består ofte av enkeltlinjede setninger som tilordner eller returnerer resultatet av et uttrykk. Den Person klassen du undersøkte tidligere i denne enheten, er et godt eksempel:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get
{
return _name != null ? _name : "NA";
}
set
{
_name = value;
}
}
}
I dette eksemplet bruker Name-egenskapen en enlinjet setning til å returnere verdien for _name feltet hvis den ikke er null, eller strengen «NA» hvis den er null. Den set accessoren bruker en enlinjet setning til å tilordne verdien for Name-egenskapen til _name-feltet.
En uttrykkstekstdefinisjon består av =>-tokenet etterfulgt av uttrykket som brukes til å tilordne eller hente egenskapsverdien. Siden accessors definert for Student klassen implementerer en enkeltlinjet setning, er det en god kandidat for oppdatering ved hjelp av uttrykkstekstdefinisjoner.
Kodesnutten nedenfor oppdaterer Student-klassen ved hjelp av uttrykkstekstdefinisjoner for get og set-tilgangsmenn:
class Student
{
private string? _name; // the name field
public string Name // the Name property
{
get => _name ?? "NA";
set => _name = value;
}
}
Feltstøttede egenskaper
Fra og med C# 13 kan du legge til validering eller annen logikk i accessor for en egenskap ved hjelp av field funksjon for forhåndsvisning av nøkkelord. Nøkkelordet field får tilgang til det syntetiserte bakfeltet for kompilatoren for en egenskap. Det gjør det mulig å skrive en egenskapstilgangsgiver uten eksplisitt å deklarere et eget støttefelt.
public class Person
{
public string? FirstName
{
get;
set => field = value.Trim();
}
// Omitted for brevity.
}
Viktig
Nøkkelordet field er en forhåndsvisningsfunksjon i C# 13. Du må bruke .NET 9 og angi at <LangVersion> elementet skal forhåndsvises i prosjektfilen for å kunne bruke det field kontekstavhengige nøkkelordet.
Du bør være forsiktig med å bruke field nøkkelordfunksjonen i en klasse som har et felt med navnet field. Det nye field-nøkkelordet skygger et felt med navnet field i omfanget til en egenskapstilgangsperson. Du kan enten endre navnet på field variabelen, eller bruke @-tokenet til å referere til feltidentifikatoren som @field.
Obligatoriske egenskaper
I det foregående eksemplet kan en innringer opprette en Person ved hjelp av standardkonstruktøren, uten å angi egenskapen FirstName. Egenskapstypen er satt til en nullstreng. Fra og med C# 11 kan du kreve at innringere angir en egenskap:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
// Omitted for brevity.
}
Den forrige koden gjør to endringer i Person klassen. Først inkluderer FirstName egenskapsdeklarasjon required modifikatoren. Det betyr at alle koder som oppretter en ny Person, må angi denne egenskapen ved hjelp av en objektinitialiserer. For det andre har konstruktøren som tar en firstName-parameter System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute attributtet. Dette attributtet informerer kompilatoren om at denne konstruktøren angir alle nødvendige medlemmer. Innringere som bruker denne konstruktøren, må ikke angi required egenskaper med en objektinitialiserer.
Viktig
Ikke forveksle required med ikke-nullbar. Det er gyldig å angi en required egenskap til null eller default. Hvis typen ikke kan nullstilles, for eksempel string i disse eksemplene, utsteder kompilatoren en advarsel.
var aPerson = new Person("PersonName");
aPerson = new Person{ FirstName = "PersonName"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();