Share via


Eigenschappen gebruiken (C#-programmeerhandleiding)

Eigenschappen combineren aspecten van zowel velden als methoden. Voor de gebruiker van een object lijkt een eigenschap een veld te zijn; Voor toegang tot de eigenschap is dezelfde syntaxis vereist. Voor de implementeerfunctie van een klasse is een eigenschap een of twee codeblokken, die een get accessor en/of een set of init accessor vertegenwoordigen. Het codeblok voor de get accessor wordt uitgevoerd wanneer de eigenschap wordt gelezen. Het codeblok voor de set of init accessor wordt uitgevoerd wanneer aan de eigenschap een waarde wordt toegewezen. Een eigenschap zonder accessor set wordt beschouwd als alleen-lezen. Een eigenschap zonder get een accessor wordt beschouwd als alleen-schrijven. Een eigenschap met beide accessors is lezen/schrijven. U kunt een init accessor gebruiken in plaats van een set accessor om de eigenschap in te stellen als onderdeel van object initialisatie, maar anders alleen-lezen te maken.

In tegenstelling tot velden worden eigenschappen niet geclassificeerd als variabelen. Daarom kunt u een eigenschap niet doorgeven als een ref of out parameter.

Eigenschappen hebben veel gebruik:

  • Ze kunnen gegevens valideren voordat ze een wijziging toestaan.
  • Ze kunnen transparant gegevens beschikbaar maken in een klasse waarin die gegevens worden opgehaald uit een andere bron, zoals een database.
  • Ze kunnen actie ondernemen wanneer gegevens worden gewijzigd, zoals het genereren van een gebeurtenis of het wijzigen van de waarde van andere velden.

Eigenschappen worden gedeclareerd in het klasseblok door het toegangsniveau van het veld op te geven, gevolgd door het type eigenschap, gevolgd door de naam van de eigenschap en gevolgd door een codeblok dat een get-accessor en/of een set accessor declareert. Voorbeeld:

public class Date
{
    private int _month = 7;  // Backing store

    public int Month
    {
        get => _month;
        set
        {
            if ((value > 0) && (value < 13))
            {
                _month = value;
            }
        }
    }
}

In dit voorbeeld Month wordt deze gedeclareerd als een eigenschap, zodat de set toegangsfunctie ervoor kan zorgen dat de Month waarde tussen 1 en 12 is ingesteld. De Month eigenschap maakt gebruik van een privéveld om de werkelijke waarde bij te houden. De werkelijke locatie van de gegevens van een eigenschap wordt vaak 'backing store' van de eigenschap genoemd. Het is gebruikelijk dat eigenschappen privévelden gebruiken als back-uparchief. Het veld is gemarkeerd als privé om ervoor te zorgen dat het alleen kan worden gewijzigd door de eigenschap aan te roepen. Zie Toegangsmodifiers voor meer informatie over beperkingen voor openbare en persoonlijke toegang. Automatisch geïmplementeerde eigenschappen bieden vereenvoudigde syntaxis voor eenvoudige eigenschapsdeclaraties. Zie Eigenschappen die automatisch zijn geïmplementeerd voor meer informatie.

De get-accessor

De hoofdtekst van de get accessor lijkt op die van een methode. Er moet een waarde van het eigenschapstype worden geretourneerd. De C#-compiler en JIT-compiler (Just-In-Time) detecteren veelvoorkomende patronen voor het implementeren van de get accessor en optimaliseert deze patronen. Een get accessor die bijvoorbeeld een veld retourneert zonder berekeningen uit te voeren, is waarschijnlijk geoptimaliseerd voor een geheugenleesbewerking van dat veld. Eigenschappen die automatisch zijn geïmplementeerd, volgen dit patroon en profiteren van deze optimalisaties. Een virtuele get accessormethode kan echter niet inline worden geplaatst omdat de compiler niet weet op het moment van compileren welke methode daadwerkelijk kan worden aangeroepen tijdens runtime. In het volgende voorbeeld ziet u een get accessor die de waarde van een privéveld _nameretourneert:

class Employee
{
    private string _name;  // the name field
    public string Name => _name;     // the Name property
}

Wanneer u naar de eigenschap verwijst, met uitzondering van het doel van een toewijzing, wordt de get toegangsservice aangeroepen om de waarde van de eigenschap te lezen. Voorbeeld:

var employee= new Employee();
//...

System.Console.Write(employee.Name);  // the get accessor is invoked here

De get toegangsfunctie moet een expressie-bodyied lid zijn, of eindigen op een retour - of throw-instructie , en het besturingselement kan niet uit de hoofdtekst van de toegangsfunctie stromen.

Waarschuwing

Het is een slechte programmeerstijl om de status van het object te wijzigen met behulp van de get accessor.

De get accessor kan worden gebruikt om de veldwaarde te retourneren of om deze te berekenen en te retourneren. Voorbeeld:

class Manager
{
    private string _name;
    public string Name => _name != null ? _name : "NA";
}

Als u in het vorige voorbeeld geen waarde aan de Name eigenschap toewijst, wordt de waarde NAgeretourneerd.

De set accessor

De set toegangsfunctie lijkt op een methode waarvan het retourtype ongeldig is. Hierbij wordt een impliciete parameter met de naam valuegebruikt, waarvan het type het type van de eigenschap is. De compiler en JIT-compiler herkennen ook veelvoorkomende patronen voor een set of init accessor. Deze algemene patronen zijn geoptimaliseerd, waarbij het geheugen voor het back-upveld rechtstreeks wordt geschreven. In het volgende voorbeeld wordt een set toegangsfunctie toegevoegd aan de Name eigenschap:

class Student
{
    private string _name;  // the name field
    public string Name    // the Name property
    {
        get => _name;
        set => _name = value;
    }
}

Wanneer u een waarde aan de eigenschap toewijst, wordt de set accessor aangeroepen met behulp van een argument dat de nieuwe waarde levert. Voorbeeld:

var student = new Student();
student.Name = "Joe";  // the set accessor is invoked here

System.Console.Write(student.Name);  // the get accessor is invoked here

Het is een fout om de impliciete parameternaam valuete gebruiken voor een lokale variabeledeclaratie in een set accessor.

De init-toegangsrechten

De code voor het maken van een init accessor is hetzelfde als de code voor het maken van een set accessor, behalve dat u het init trefwoord gebruikt in plaats van set. Het verschil is dat de init accessor alleen kan worden gebruikt in de constructor of met behulp van een object-initializer.

Opmerkingen

Eigenschappen kunnen worden gemarkeerd als public, private, protected, internal, , protected internalof private protected. Deze toegangsaanpassingen definiëren hoe gebruikers van de klasse toegang hebben tot de eigenschap. De get en set accessors voor dezelfde eigenschap kunnen verschillende toegangsaanpassingen hebben. Het kan bijvoorbeeld get zijn dat alleen-lezentoegang van buiten het type is toegestaan, en het set kan of privateprotectedpublic. Zie Toegangsmodifiers voor meer informatie.

Een eigenschap kan worden gedeclareerd als een statische eigenschap met behulp van het static trefwoord. Statische eigenschappen zijn op elk gewenst moment beschikbaar voor bellers, zelfs als er geen exemplaar van de klasse bestaat. Zie Statische klassen en statische klasseleden voor meer informatie.

Een eigenschap kan worden gemarkeerd als een virtuele eigenschap met behulp van het virtuele trefwoord. Met virtuele eigenschappen kunnen afgeleide klassen het gedrag van de eigenschap overschrijven met behulp van het trefwoord overschrijven . Zie Overname voor meer informatie over deze opties.

Een eigenschap die een virtuele eigenschap overschrijft, kan ook worden verzegeld, wat aangeeft dat deze niet meer virtueel is voor afgeleide klassen. Ten slotte kan een eigenschap worden gedeclareerd als abstract. Abstracte eigenschappen definiëren geen implementatie in de klasse en afgeleide klassen moeten hun eigen implementatie schrijven. Zie Abstracte en verzegelde klassen en klasleden voor meer informatie over deze opties.

Notitie

Het is een fout bij het gebruik van een virtuele, abstracte of onderdrukkingsaanpassing voor een toegangsfunctie van een statische eigenschap.

Voorbeelden

In dit voorbeeld ziet u de eigenschappen exemplaar, statisch en alleen-lezen. Hiermee wordt de naam van de werknemer van het toetsenbord geaccepteerd, wordt verhoogd NumberOfEmployees met 1 en wordt de naam en het nummer van de werknemer weergegeven.

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:
}

Voorbeeld van verborgen eigenschap

In dit voorbeeld ziet u hoe u toegang krijgt tot een eigenschap in een basisklasse die wordt verborgen door een andere eigenschap met dezelfde naam in een afgeleide klasse:

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
*/

Dit zijn belangrijke punten in het vorige voorbeeld:

  • De eigenschap Name in de afgeleide klasse verbergt de eigenschap Name in de basisklasse. In dat geval wordt de new wijzigingsfunctie gebruikt in de declaratie van de eigenschap in de afgeleide klasse:
    public new string Name
    
  • De cast (Employee) wordt gebruikt voor toegang tot de verborgen eigenschap in de basisklasse:
    ((Employee)m1).Name = "Mary";
    

Zie de nieuwe modifier voor meer informatie over het verbergen van leden.

Voorbeeld van onderdrukkingseigenschap

In dit voorbeeld implementeren twee klassen Cube en Squareimplementeert u een abstracte klasse Shapeen overschrijft u de abstracte Area eigenschap. Let op het gebruik van de onderdrukkingsaanpassing op de eigenschappen. Het programma accepteert de zijkant als invoer en berekent de gebieden voor het vierkant en de kubus. Het gebied wordt ook geaccepteerd als invoer en berekent de bijbehorende zijde voor het vierkant en de kubus.

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
*/

Zie ook