Udostępnij za pośrednictwem


Właściwości (Przewodnik programowania w języku C#)

Właściwość jest elementem członkowskim, który zapewnia elastyczny mechanizm odczytu, zapisu lub obliczania wartości pola danych. Właściwości są wyświetlane jako elementy członkowskie danych publicznych, ale są implementowane jako specjalne metody nazywane metodami 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. Składnia właściwości to naturalne rozszerzenie pól. Pole definiuje lokalizację magazynu:

public class Person
{
    public string? FirstName;

    // Omitted for brevity.
}

Automatycznie zaimplementowane właściwości

Definicja właściwości zawiera deklaracje metody get i set , która pobiera i przypisuje wartość tej właściwości:

public class Person
{
    public string? FirstName { get; set; }

    // Omitted for brevity.
}

W poprzednim przykładzie przedstawiono automatycznie zaimplementowaną właściwość. Kompilator generuje ukryte pole zapasowe dla właściwości . Kompilator implementuje również treść elementów get i set metod dostępu. Wszystkie atrybuty są stosowane do automatycznie zaimplementowanej właściwości. Atrybut można zastosować do pola kopii zapasowej wygenerowanego przez kompilator, określając field: tag atrybutu.

Właściwość można zainicjować na wartość inną niż domyślna, ustawiając wartość po zamykającym nawiasie klamrowym dla właściwości. Możesz preferować początkową wartość FirstName właściwości jako pusty ciąg, a nie null. Należy określić to, jak pokazano w poniższym kodzie:

public class Person
{
    public string FirstName { get; set; } = string.Empty;

    // Omitted for brevity.
}

Właściwości kopii zapasowej pola

W języku 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 field kluczowe 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ż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.

Wymagane właściwości

W poprzednim przykładzie obiekt wywołujący może utworzyć Person obiekt wywołujący przy użyciu konstruktora domyślnego bez ustawiania FirstName właściwości . Właściwość zmieniła typ 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 Person klasie. FirstName Najpierw deklaracja właściwości zawiera required modyfikator. Oznacza to, że każdy kod tworzący nową Person właściwość musi ustawić tę właściwość przy użyciu inicjatora obiektów. Po drugie, konstruktor, który przyjmuje firstName parametr, ma System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute atrybut . Ten atrybut informuje kompilator, że ten konstruktor ustawia wszystkie required elementy członkowskie. Obiekty wywołujące używające tego konstruktora nie są wymagane do ustawiania required właściwości za pomocą inicjatora obiektu.

Ważne

Nie należy mylić required z wartością niepustą. Prawidłowe jest ustawienie required właściwości na null lub default. Jeśli typ jest niepusty, taki jak string w tych przykładach, kompilator wyświetla ostrzeżenie.

var aPerson = new Person("John");
aPerson = new Person{ FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();

Definicje treści wyrażeń

Metody dostępu do właściwości często składają się z instrukcji jednowierszowych. Metody dostępu przypisują lub zwracają wynik wyrażenia. Te właściwości można zaimplementować jako elementy członkowskie wyrażeń. Definicje treści wyrażeń składają się z tokenu => , po którym następuje wyrażenie, które ma zostać przypisane do właściwości lub pobrane z tej właściwości.

Właściwości tylko do odczytu mogą implementować metodę get dostępu jako składową typu wyrażenie-bodied. Poniższy przykład implementuje właściwość tylko Name do odczytu jako składową typu wyrażenie-bodied:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    public string Name => $"{FirstName} {LastName}";

    // Omitted for brevity.
}

Właściwość Name jest właściwością obliczoną. Nie ma pola tworzenia kopii zapasowej dla elementu Name. Właściwość oblicza ją za każdym razem.

Kontrola dostępu

W poprzednich przykładach pokazano właściwości odczytu/zapisu. Można również utworzyć właściwości tylko do odczytu lub zapewnić różne ułatwienia dostępu do zestawu i uzyskać metody dostępu. Załóżmy, że klasa Person powinna włączać tylko zmianę wartości FirstName właściwości z innych metod w klasie. Można nadać zestaw dostępu dostępu private zamiast internal lub public:

public class Person
{
    public string? FirstName { get; private set; }

    // Omitted for brevity.
}

Właściwość FirstName można odczytać z dowolnego kodu, ale można ją przypisać tylko z kodu w Person klasie.

Możesz dodać dowolny restrykcyjny modyfikator dostępu do zestawu lub uzyskać metody dostępu. Modyfikator dostępu do poszczególnych metod dostępu musi być bardziej restrykcyjny niż dostęp do właściwości. Powyższy kod jest legalny, ponieważ FirstName właściwość to public, ale zestaw metod dostępu to private. Nie można zadeklarować private właściwości za pomocą public metody dostępu. Deklaracje właściwości można również zadeklarować protected, internal, protected internal, lub nawet private.

Istnieją dwa specjalne modyfikatory dostępu dla set metod dostępu:

  • Akcesorium set może mieć init jako modyfikator dostępu. Ta set metoda dostępu może być wywoływana tylko z inicjatora obiektu lub konstruktorów typu. Jest bardziej restrykcyjny niż private na akcesorium set .
  • Właściwość zaimplementowana automatycznie może zadeklarować metodę get dostępu bez set metody dostępu. W takim przypadku kompilator umożliwia set wywoływanie metody dostępu tylko z konstruktorów typu. Jest bardziej restrykcyjny niż init akcesorium na akcesorium set .

Zmodyfikuj klasę w Person następujący sposób:

public class Person
{
    public Person(string firstName) => FirstName = firstName;

    public string FirstName { get; }

    // Omitted for brevity.
}

Powyższy przykład wymaga, aby wywołujący używali konstruktora zawierającego FirstName parametr . Obiekt wywołujący nie może użyć inicjatorów obiektów do przypisania wartości do właściwości. Aby obsługiwać inicjatory, można ustawić metodę set init dostępu, jak pokazano w poniższym kodzie:

public class Person
{
    public Person() { }
    public Person(string firstName) => FirstName = firstName;

    public string? FirstName { get; init; }

    // Omitted for brevity.
}

Modyfikatory te są często używane z modyfikatorem, aby wymusić właściwą inicjację required .

Właściwości z polami zapasowymi

Można mieszać koncepcję obliczonej właściwości z polem prywatnym i utworzyć buforowane oceniane właściwości. Na przykład zaktualizuj FullName właściwość, aby formatowanie ciągu odbywało się przy pierwszym dostępie:

public class Person
{
    public Person() { }

    [SetsRequiredMembers]
    public Person(string firstName, string lastName)
    {
        FirstName = firstName;
        LastName = lastName;
    }

    public required string FirstName { get; init; }
    public required string LastName { get; init; }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Ta implementacja działa, ponieważ FirstName właściwości i LastName są tylko do odczytu. Użytkownicy mogą zmienić swoje imię i nazwisko. FirstName Zaktualizowanie właściwości i LastName w celu zezwolenia na set metody dostępu wymaga unieważnienia dowolnej wartości buforowanej dla elementu fullName. Zmodyfikujesz set FirstName metody dostępu właściwości i LastName , aby fullName pole zostało ponownie obliczone:

public class Person
{
    private string? _firstName;
    public string? FirstName
    {
        get => _firstName;
        set
        {
            _firstName = value;
            _fullName = null;
        }
    }

    private string? _lastName;
    public string? LastName
    {
        get => _lastName;
        set
        {
            _lastName = value;
            _fullName = null;
        }
    }

    private string? _fullName;
    public string FullName
    {
        get
        {
            if (_fullName is null)
                _fullName = $"{FirstName} {LastName}";
            return _fullName;
        }
    }
}

Ta ostateczna FullName wersja ocenia właściwość tylko wtedy, gdy jest to konieczne. Poprzednio obliczona wersja jest używana, jeśli jest prawidłowa. W przeciwnym razie obliczenie aktualizuje buforowane wartości. Deweloperzy korzystający z tej klasy nie muszą znać szczegółów implementacji. Żadne z tych zmian wewnętrznych nie ma wpływu na użycie obiektu Person.

Począwszy od języka C# 13, można tworzyć partial właściwości w partial klasach. Deklaracja implementowania właściwości partial nie może być automatycznie zaimplementowaną właściwością. Właściwość zaimplementowana automatycznie używa tej samej składni co deklarowanie deklaracji właściwości częściowej.

Właściwości

Właściwości są formą pól inteligentnych w klasie lub obiekcie. Z zewnątrz obiektu są one wyświetlane jak pola w obiekcie. Można jednak zaimplementować właściwości przy użyciu pełnej palety funkcji języka C#. Możesz zapewnić walidację, różne ułatwienia dostępu, leniwą ocenę lub wszelkie wymagania wymagane przez scenariusze.

  • Proste właściwości, które nie wymagają niestandardowego kodu dostępu, można zaimplementować jako definicje treści wyrażenia lub automatycznie zaimplementowane właściwości.
  • Właściwości umożliwiają klasie uwidacznianie publicznego sposobu uzyskiwania i ustawiania wartości podczas ukrywania implementacji lub kodu weryfikacyjnego.
  • Metodę dostępu do właściwości get służy do zwracania wartości właściwości, a element dostępu właściwości zestawu służy do przypisywania nowej wartości. Akcesor właściwości init służy do przypisywania nowej wartości tylko podczas budowy obiektu. Te metody dostępu mogą mieć różne poziomy dostępu. Aby uzyskać więcej informacji, zobacz Ograniczanie ułatwień dostępu dostępu.
  • Słowo kluczowe value służy do definiowania wartości set przypisywanej przez metodę lub init metody dostępu.
  • Właściwości mogą być do odczytu i zapisu (mają zarówno get metodę dostępu, jak i set metodę dostępu), tylko do odczytu (mają get metodę dostępu, ale bez set metody dostępu) lub tylko do zapisu (mają set akcesorium, ale bez get akcesoriów). Właściwości tylko do zapisu są rzadkie.

Specyfikacja języka C#

Aby uzyskać więcej informacji, zobacz Właściwości w specyfikacji języka C#. Specyfikacja języka jest ostatecznym źródłem informacji o składni i użyciu języka C#.

Zobacz też