Заметка
Доступ к этой странице требует авторизации. Вы можете попробовать войти в систему или изменить каталог.
Доступ к этой странице требует авторизации. Вы можете попробовать сменить директорию.
Свойство — это элемент, предоставляющий гибкий механизм для чтения, записи или вычисления значения поля данных. Свойства отображаются как открытые элементы данных, но они реализуются как специальные методы, называемые аксессорами. Эта функция позволяет вызывающим пользователям легко получать доступ к данным и по-прежнему способствовать обеспечению безопасности и гибкости данных. Синтаксис свойств является естественным расширением полей. Поле определяет место хранения:
public class Person
{
public string? FirstName;
// Omitted for brevity.
}
Автоматически реализованные свойства
Определение свойства содержит объявления для методов доступа get и set, которые получают и устанавливают значение этого свойства:
public class Person
{
public string? FirstName { get; set; }
// Omitted for brevity.
}
В предыдущем примере показано автоматически реализованное свойство. Компилятор создает скрытое поле резервного копирования для свойства. Компилятор также реализует тело аксессоров get и set. Все атрибуты применяются к автоматически реализуемому свойству. Атрибут можно применить к поле резервной копии, созданному компилятором, указав field: тег атрибута.
Можно инициализировать свойство до значения, отличного от значения по умолчанию, задав значение после закрывающей фигурной скобки свойства. Вы можете предпочесть, чтобы начальным значением свойства FirstName была пустая строка, чем null. Как показано в следующем коде, это можно указать следующим образом:
public class Person
{
public string FirstName { get; set; } = string.Empty;
// Omitted for brevity.
}
Свойства, поддерживаемые полем
В C# 14 вы можете добавить проверку или другую логику в аксессор свойства с помощью ключевого слова field. Ключевое field слово обращается к синтезированному полю резервного копирования компилятора для свойства. Он позволяет создавать метод доступа к свойствам без явного объявления отдельного поля резервного копирования.
public class Person
{
public string? FirstName
{
get;
set => field = value.Trim();
}
// Omitted for brevity.
}
Обязательные свойства
В приведенном выше примере вызывающий объект может создать экземпляр Person с использованием конструктора по умолчанию, не устанавливая свойство FirstName. Свойство изменило тип на строку, которая может быть null. Для задания свойства можно требовать, чтобы вызывающие пользователи могли задать свойство:
public class Person
{
public Person() { }
[SetsRequiredMembers]
public Person(string firstName) => FirstName = firstName;
public required string FirstName { get; init; }
// Omitted for brevity.
}
Предыдущий код вносит два изменения в Person класс. Во-первых, FirstName объявление свойства включает required модификатор. Это означает, что любой код, создающий новое Person свойство, должен задать это свойство с помощью инициализатора объектов. Во-вторых, конструктор, принимаюющий firstName параметр, имеет System.Diagnostics.CodeAnalysis.SetsRequiredMembersAttribute атрибут. Этот атрибут сообщает компилятору, что этот конструктор задает всеrequired элементы. Вызывающим этот конструктор не обязательно использовать инициализатор объектов для задания свойств required.
Внимание
Не путайте required с ненулевой. Допустимо задать свойству required значение null или default. Если тип не допускает значение NULL, например string в этих примерах, компилятор выдает предупреждение.
var aPerson = new Person("John");
aPerson = new Person { FirstName = "John"};
// Error CS9035: Required member `Person.FirstName` must be set:
//aPerson2 = new Person();
Определения текста выражений
Методы доступа к свойствам часто состоят из однострочных инструкций. Методы доступа присваивают или возвращают результат выражения. Эти свойства можно реализовать как члены, воплощающие выражение. Определения тела выражения состоят из маркера =>, за которым следует выражение, которое назначается свойству или извлекается из него.
Свойства, доступные только для чтения, могут реализовать get аксессор в виде выражения. В следующем примере реализуется свойство только для Name чтения в качестве элемента, наследуемого выражением:
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.
}
Name — вычисляемое свойство. Нет резервного поля для Name. Свойство вычисляет его каждый раз.
Управление доступом
В предыдущих примерах показаны свойства чтения и записи. Вы также можете создать свойства только для чтения или задать разные уровни доступа для методов доступа set и get. Предположим, что класс Person должен позволять изменять значение свойства FirstName только в других методах класса. Вы можете предоставить доступность аксессора set для private, вместо internal или public.
public class Person
{
public string? FirstName { get; private set; }
// Omitted for brevity.
}
Свойство FirstName можно считывать из любого кода, но его можно назначить только из кода в Person классе.
Вы можете добавить любой ограничивающий модификатор доступа к аксессорам set или get. Модификатор доступа для отдельного метода доступа должен быть более строгим, чем доступ к свойству. Предыдущий код является законным, так как свойство FirstName является public, но свойство set является private. Нельзя объявить private свойство с public аксессором. Свойство также можно объявить как protected, internal, protected internal или даже private.
Существует два специальных модификатора доступа для set аксессоров:
- Аксессор
setможет использоватьinitкак модификатор доступа. Этотsetаксессор можно вызывать только из инициализатора объекта или конструкторов типа. Это более строго, чемprivateнаsetаксессоре. - Автоматически реализованное свойство может объявлять
getаксессор безsetаксессора. В этом случае компилятор позволяет вызывать аксессор только из конструкторов типа. Это более ограничительно, чемinitмодификатор доступа наset.
Измените Person класс следующим образом:
public class Person
{
public Person(string firstName) => FirstName = firstName;
public string FirstName { get; }
// Omitted for brevity.
}
В предыдущем примере требуется, чтобы вызывающие использовали конструктор, включающий параметр FirstName. Вызывающие не могут использовать инициализаторы объектов для назначения значения свойству. Для поддержки инициализаторов можно сделать аксессор set аксессором init, как показано в следующем коде:
public class Person
{
public Person() { }
public Person(string firstName) => FirstName = firstName;
public string? FirstName { get; init; }
// Omitted for brevity.
}
Эти модификаторы часто используются с модификатором required для принудительной инициализации.
Свойства с резервными полями
Вы можете смешать концепцию вычисляемого свойства с частным полем и создать кэшированное вычисляемое свойство. Например, обновите FullName свойство таким образом, чтобы строковое форматирование происходило при первом доступе:
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;
}
}
}
Эта реализация работает, потому что свойства FirstName и LastName доступны только для чтения. Люди могут изменить свое имя. Обновление свойств FirstName и LastName для разрешения set доступа требует аннулирования любого кэшированного значения для fullName. Вы изменяете set и FirstName методы доступа свойства LastName, чтобы fullName поле вычислялось снова:
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;
}
}
}
Эта окончательная версия вычисляет свойство FullName только при необходимости. Если это допустимо, используется ранее вычисляемая версия. В противном случае вычисление обновляет кэшированное значение. Разработчикам, использующим этот класс, не нужно знать подробности реализации. Ни одно из этих внутренних изменений не влияет на использование объекта Person.
Начиная с C# 13, можно создавать partial свойства в partial классах. Объявление реализации для partial свойства не может быть автоматически реализованным свойством. Автоматически реализованное свойство использует тот же синтаксис, что и объявление частичного свойства.
Свойства
Свойства — это своего рода интеллектуальные поля в классе или объекте. Из-за пределов объекта они представляются полями в объекте. Однако для реализации свойства можно использовать полную палитру функциональных возможностей C#. Вы можете предоставлять проверку правильности, различные возможности доступа, отложенное вычисление или любые другие требования, необходимые в ваших сценариях.
- Простые свойства, для которых не требуется пользовательский код доступа, можно реализовать как определения текста выражения или как автоматически реализованные свойства.
- Свойства позволяют классу предоставлять общий способ получения и задания значений, скрывая при этом код реализации или проверки.
- Метод доступа get используется для возврата значения свойства, а метод доступа set — для присвоения нового значения. Метод доступа к свойству init используется для назначения нового значения только во время построения объекта. Эти акцессоры могут иметь различные уровни доступа. Дополнительные сведения см. в разделе Ограничение доступности аксессоров.
- Ключевое слово value используется для определения значения, которое назначается методом доступа
setилиinit. - Свойства могут быть доступны для чтения и записи (они имеют оба метода доступа —
getиset), только для чтения (они имеют метод доступаget, но не имеют метода доступаset) или только для записи (они имеют метод доступаset, но не имеют метода доступаget). Свойства, доступные только для записи, редки.
Спецификация языка C#
Дополнительные сведения см. в разделе Свойства в Спецификации языка C#. Спецификация языка является авторитетным источником синтаксиса и использования C#.