Använda egenskaper (C#-programmeringsguide)
Egenskaper kombinerar aspekter av både fält och metoder. För användaren av ett objekt verkar en egenskap vara ett fält. Åtkomst till egenskapen kräver samma syntax. För implementeraren för en klass är en egenskap ett eller två kodblock som representerar en get
accessor och/eller en eller init
en set
accessor. Kodblocket get
för accessorn körs när egenskapen läss. Kodblocket för set
eller-accessorn init
körs när egenskapen tilldelas ett värde. En egenskap utan set
åtkomst anses vara skrivskyddad. En egenskap utan en get
accessor betraktas som skrivskyddad. En egenskap som har båda åtkomsterna är skrivskyddad. Du kan använda en init
accessor i stället för en set
accessor för att aktivera att egenskapen anges som en del av objektinitiering, men annars göra den skrivskyddad.
Till skillnad från fält klassificeras inte egenskaper som variabler. Därför kan du inte skicka en egenskap som en ref
eller out
-parameter.
Egenskaper har många användningsområden:
- De kan verifiera data innan de tillåter en ändring.
- De kan transparent exponera data i en klass där dessa data hämtas från någon annan källa, till exempel en databas.
- De kan vidta en åtgärd när data ändras, till exempel att skapa en händelse eller ändra värdet för andra fält.
Egenskaper deklareras i klassblocket genom att ange åtkomstnivån för fältet, följt av egenskapens typ, följt av namnet på egenskapen och följt av ett kodblock som deklarerar en get
-accessor och/eller en set
accessor. Till exempel:
public class Date
{
private int _month = 7; // Backing store
public int Month
{
get => _month;
set
{
if ((value > 0) && (value < 13))
{
_month = value;
}
}
}
}
I det här exemplet Month
deklareras som en egenskap så att set
användaren kan se till att Month
värdet anges mellan 1 och 12. Egenskapen Month
använder ett privat fält för att spåra det faktiska värdet. Den verkliga platsen för en egenskaps data kallas ofta för egenskapens "backningslager". Det är vanligt att egenskaper använder privata fält som ett lagringsarkiv. Fältet är markerat som privat för att se till att det bara kan ändras genom att anropa egenskapen. Mer information om begränsningar för offentlig och privat åtkomst finns i Åtkomstmodifierare. Automatiskt implementerade egenskaper ger förenklad syntax för enkla egenskapsdeklarationer. Mer information finns i Automatiskt implementerade egenskaper.
Från och med C# 13 kan du använda fältstödda egenskaper för att lägga till validering i åtkomstgivaren för set
en automatiskt implementerad egenskap, som du ser i följande exempel:
public class DateExample
{
public int Month
{
get;
set
{
if ((value > 0) && (value < 13))
{
field = value;
}
}
}
}
Viktigt!
Nyckelordet field
är en förhandsgranskningsfunktion i C# 13. Du måste använda .NET 9 och ange <LangVersion>
elementet till preview
i projektfilen för att kunna använda det kontextuella nyckelordet field
.
Du bör vara försiktig med att använda nyckelordsfunktionen field
i en klass som har ett fält med namnet field
. Det nya field
nyckelordet skuggar ett fält med namnet field
i omfånget för en egenskapsåtkomst. Du kan antingen ändra namnet på variabeln field
eller använda @
token för att referera till identifieraren field
som @field
. Du kan läsa mer genom att läsa funktionsspecifikationen för nyckelordetfield
.
Hämta-accessorn
Accessorns get
brödtext liknar den för en metod. Det måste returnera ett värde av egenskapstypen. Kompilatorn C#-kompilatorn och JIT-kompilatorn (Just-in-time) identifierar vanliga mönster för att implementera get
accessorn och optimerar dessa mönster. Till exempel optimeras en get
accessor som returnerar ett fält utan att utföra någon beräkning till en minnesläsning av det fältet. Automatiskt implementerade egenskaper följer det här mönstret och drar nytta av dessa optimeringar. Det går dock inte att infoga en virtuell get
accessor-metod eftersom kompilatorn inte vet vid kompileringstillfället vilken metod som faktiskt kan anropas vid körning. I följande exempel visas en get
accessor som returnerar värdet för ett privat fält _name
:
class Employee
{
private string _name; // the name field
public string Name => _name; // the Name property
}
När du refererar till egenskapen, förutom som mål för en tilldelning, get
anropas accessorn för att läsa värdet för egenskapen. Till exempel:
var employee= new Employee();
//...
System.Console.Write(employee.Name); // the get accessor is invoked here
Accessorn get
måste vara en uttryckskroppsmedlem, eller sluta i en retur - eller throw-instruktion , och kontrollen kan inte flöda från accessor-brödtexten.
Varning
Det är vanligtvis ett dåligt programmeringsformat för att ändra objektets tillstånd med hjälp get
av accessorn. Ett undantag till den här regeln är en lat utvärderad egenskap, där värdet för en egenskap endast beräknas när den först används.
Accessorn get
kan användas för att returnera fältvärdet eller för att beräkna det och returnera det. Till exempel:
class Manager
{
private string _name;
public string Name => _name != null ? _name : "NA";
}
Om du inte tilldelar egenskapen något värde Name
i föregående exempel returneras värdet NA
.
Set-åtkomstorn
Accessorn set
liknar en metod vars returtyp är tom. Den använder en implicit parameter med namnet value
, vars typ är egenskapens typ. Kompilatorn och JIT-kompilatorn känner också igen vanliga mönster för en eller init
en set
accessor. Dessa vanliga mönster är optimerade och skriver direkt minnet för bakgrundsfältet. I följande exempel läggs en set
accessor till i egenskapen Name
:
class Student
{
private string _name; // the name field
public string Name // the Name property
{
get => _name;
set => _name = value;
}
}
När du tilldelar egenskapen ett värde set
anropas accessorn med hjälp av ett argument som ger det nya värdet. Till exempel:
var student = new Student();
student.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(student.Name); // the get accessor is invoked here
Det är ett fel att använda det implicita parameternamnet , value
för en lokal variabeldeklaration i en set
accessor.
Init-åtkomstorn
Koden för att skapa en init
accessor är samma som koden för att skapa en set
accessor förutom att du använder nyckelordet init
i stället för set
. Skillnaden är att init
accessorn endast kan användas i konstruktorn eller med hjälp av en objektinitierare.
Kommentarer
Egenskaper kan markeras som public
, private
, protected
, internal
, protected internal
eller private protected
. Dessa åtkomstmodifierare definierar hur användare av klassen kan komma åt egenskapen. Accessorerna get
och set
för samma egenskap kan ha olika åtkomstmodifierare. Till exempel get
kan vara public
att tillåta skrivskyddad åtkomst utanför typen och set
kan vara private
eller protected
. Mer information finns i Åtkomstmodifierare.
En egenskap kan deklareras som en statisk egenskap med hjälp av nyckelordet static
. Statiska egenskaper är tillgängliga för anropare när som helst, även om det inte finns någon instans av klassen. Mer information finns i Statiska klasser och Statiska klassmedlemmar.
En egenskap kan markeras som en virtuell egenskap med hjälp av det virtuella nyckelordet. Med virtuella egenskaper kan härledda klasser åsidosätta egenskapsbeteendet med hjälp av nyckelordet åsidosättning . Mer information om dessa alternativ finns i Arv.
En egenskap som åsidosätter en virtuell egenskap kan också förseglas och ange att den inte längre är virtuell för härledda klasser. Slutligen kan en egenskap förklaras abstrakt. Abstrakta egenskaper definierar inte någon implementering i klassen, och härledda klasser måste skriva sin egen implementering. Mer information om dessa alternativ finns i Abstrakta och förseglade klasser och klassmedlemmar.
Kommentar
Det är ett fel att använda en virtuell, abstrakt eller åsidosättningsmodifierare på en accessor för en statisk egenskap.
Exempel
Det här exemplet visar egenskaper för instanser, statiska och skrivskyddade. Den accepterar namnet på medarbetaren från tangentbordet, ökar med NumberOfEmployees
1 och visar medarbetarens namn och nummer.
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:
}
Exempel på dold egenskap
Det här exemplet visar hur du får åtkomst till en egenskap i en basklass som är dold av en annan egenskap som har samma namn i en härledd klass:
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
*/
Följande är viktiga punkter i föregående exempel:
- Egenskapen
Name
i den härledda klassen döljer egenskapenName
i basklassen. I sådana fallnew
används modifieraren i deklarationen av egenskapen i den härledda klassen:public new string Name
- Gjutningen
(Employee)
används för att komma åt den dolda egenskapen i basklassen:((Employee)m1).Name = "Mary";
Mer information om hur du döljer medlemmar finns i den nya modifieraren.
Exempel på åsidosättningsegenskap
I det här exemplet implementerar två klasser, Cube
och Square
, en abstrakt klass, Shape
och åsidosätter dess abstrakta Area
egenskap. Observera användningen av åsidosättningsmodifieraren för egenskaperna. Programmet accepterar sidan som indata och beräknar områdena för kvadraten och kuben. Den accepterar också området som indata och beräknar motsvarande sida för kvadraten och kuben.
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
*/