Использование свойств (Руководство по программированию в C#)
Свойства объединяют функции полей и методов. Для объекта, использующего какой-либо объект, свойство является полем, поэтому для доступа к свойству требуется тот же синтаксис, что и для поля. Для средства реализации класса свойство является одним или двумя блоками кода, представляющими метод доступа get и/или метод доступа set. Блок кода для метода доступа get выполняется, когда осуществляется чтение свойства; блок кода для метода доступа set выполняется, когда свойству присваивается новое значение. Свойство без метода доступа set считается доступным только для чтения. Свойство без метода доступа get считается доступным только для чтения. Свойство с обоими методами доступа доступно для чтения и для записи.
В отличие от полей свойства не классифицируются как переменные. Поэтому свойство нельзя передать в качестве параметра ref (Справочник по C#) или out (Справочник по C#).
Свойства имеют множество применений: с их помощью можно проверить данные перед разрешением изменения, они могут прозрачно представлять данные в классе, куда эти данные извлекаются из какого-либо другого источника, например базы данных, они могут выполнять действие при изменении данных, например вызов события или изменение значения в других полях.
Свойства объявляются в блоке класса с помощью последовательного указания уровня доступа для поля, типа свойства, имени свойства и блока кода, в котором объявляется метод доступа get и/или set. Примеры.
public class Date
{
private int month = 7; // Backing store
public int Month
{
get
{
return month;
}
set
{
if ((value > 0) && (value < 13))
{
month = value;
}
}
}
}
В данном примере Month объявляется как свойство, поэтому метод доступа set может обеспечить задание для свойства Month значения от 1 до 12. Свойство Month использует частное поле для отслеживания фактического значения. Фактическое местоположение данных свойства часто называется "резервным хранилищем" этого свойства. Обычно в качестве резервного хранилища свойств используются частные поля. Поле помечается как частное для того, чтобы предотвратить изменение других полей при вызове данного свойства. Дополнительные сведения об ограничениях общего и закрытого доступа см. в разделе Модификаторы доступа (Руководство по программированию в C#).
Автоматически реализуемые свойства позволяют использовать упрощенный синтаксис для простых объявлений свойств. Дополнительные сведения см. в разделе Автоматически реализуемые свойства (Руководство по программированию на C#).
Метод доступа get
Основная часть метода доступа get похожа на основную часть метода. Она должна возвращать значение типа свойства. Выполнение метода доступа get эквивалентно считыванию значения поля. Например, когда возвращается частная переменная из метода доступа get и разрешена оптимизация, вызов метода доступа get встраивается компилятором, что позволяет избежать ненужных затрат на вызов метода. Однако виртуальный метод доступа get не может быть встроен, поскольку во время компиляции у компилятора нет данных о том, какой метод может быть вызван во время выполнения. Ниже приведен метод доступа get, который возвращает значение частного поля name:
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
}
}
При создании ссылки на свойство, кроме случая присвоения ему значения, для чтения значения свойства вызывается метод доступа get. Примеры.
Person person = new Person();
//...
System.Console.Write(person.Name); // the get accessor is invoked here
Метод доступа get должен заканчиваться оператором return или throw, а элемент управления не должен выходить за основную часть метода доступа.
Изменение состояния объекта с помощью метода доступа get указывает на низкую квалификацию программиста. Например, следующий метод доступа имеет побочный эффект, заключающийся в изменении состояния объекта при каждой операции доступа к полю number.
private int number;
public int Number
{
get
{
return number++; // Don't do this
}
}
Метод доступа get можно использовать для возвращения значения поля или для вычисления и возвращения этого значения. Примеры.
class Employee
{
private string name;
public string Name
{
get
{
return name != null ? name : "NA";
}
}
}
Если в предыдущем фрагменте кода свойству Name не назначается какое-либо значение, это свойство возвращает значение "NA".
Метод доступа set
Метод доступа set похож на метод, имеющий тип возвращаемого значения void. В нем используется неявный параметр value, тип которого соответствует типу свойства. В следующем примере метод доступа set добавляется в свойство Name:
class Person
{
private string name; // the name field
public string Name // the Name property
{
get
{
return name;
}
set
{
name = value;
}
}
}
Когда свойству присваивается значение, выполняется вызов метода доступа set с помощью аргумента, предоставляющего новое значение. Примеры.
Person person = new Person();
person.Name = "Joe"; // the set accessor is invoked here
System.Console.Write(person.Name); // the get accessor is invoked here
Использование имени неявного параметра value для объявления локальной переменной в методе доступа set является ошибкой.
Заметки
Свойства можно пометить как public, private, protected, internal или protected internal. Эти модификаторы доступа определяют порядок доступа к свойству для пользователей класса. Методы доступа get и set могут иметь различные модификаторы доступа для одного свойства. Например, метод доступа get может иметь модификатор public для разрешения доступа только для чтения из типа, а метод доступа set может иметь модификатор private или protected. Дополнительные сведения см. в разделе Модификаторы доступа (Руководство по программированию в C#).
Свойство можно объявить как статическое свойство при помощи ключевого слова static. При этом свойство становится доступным для вызова в любое время, даже если экземпляр класса отсутствует. Дополнительные сведения см. в разделе Статические классы и члены статических классов (Руководство по программированию в C#).
Свойство можно пометить как статическое свойство при помощи ключевого слова virtual. Это позволяет производным классам переопределять поведение свойства при помощи ключевого слова override. Дополнительные сведения об этих параметрах содержатся в разделе Наследование (Руководство по программированию на C#).
Свойство, переопределяющее виртуальное свойство, может также быть sealed, что указывает на то, что для производных классов оно более не является виртуальным. И наконец, свойство можно объявить как abstract. Это означает, что в классе отсутствует реализация, поэтому производные классы должны создавать свою собственную реализацию. Дополнительные сведения об этих параметрах содержатся в разделе Абстрактные и запечатанные классы и члены классов (Руководство по программированию на C#).
Примечание
Использование модификатора virtual (Справочник по C#), abstract (Справочник по C#) или override (Справочник по C#) для метода доступа свойства static является ошибкой.
Пример
В данном примере демонстрируются свойства экземпляра, статические свойства и свойства, доступные только для чтения. Данный код принимает имя сотрудника, введенное с клавиатуры, увеличивает на 1 значение NumberOfEmployees и отображает имя и номер сотрудника.
public class Employee
{
public static int NumberOfEmployees;
private static int counter;
private string name;
// A read-write instance property:
public string Name
{
get { return name; }
set { name = value; }
}
// A read-only static property:
public static int Counter
{
get { return counter; }
}
// A Constructor:
public Employee()
{
// Calculate the employee's number:
counter = ++counter + NumberOfEmployees;
}
}
class TestEmployee
{
static void Main()
{
Employee.NumberOfEmployees = 107;
Employee e1 = new Employee();
e1.Name = "Claude Vige";
System.Console.WriteLine("Employee number: {0}", Employee.Counter);
System.Console.WriteLine("Employee name: {0}", e1.Name);
}
}
/* Output:
Employee number: 108
Employee name: Claude Vige
*/
В данном примере демонстрируется доступ к свойству в базовом классе, которое скрыто другим свойством, имеющим такое же имя в производном классе.
public class Employee
{
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
public class Manager : Employee
{
private string name;
// Notice the use of the new modifier:
public new string Name
{
get { return name; }
set { name = value + ", Manager"; }
}
}
class TestHiding
{
static void Main()
{
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
*/
Далее перечислены важные замечания по предыдущему примеру:
Свойство Name в производном классе скрыто свойством Name в базовом классе. В этом случае модификатор new используется в объявлении свойства в производном классе:
public new string Name
Приведение (Employee) используется для доступа к скрытому свойству в базовом классе:
((Employee)m1).Name = "Mary";
Дополнительные сведения о скрытии членов см. в разделе Модификатор new (Справочник по C#).
В данном примере два класса Cube и Square реализуют абстрактный класс Shape и переопределяют его абстрактное свойство Area. Обратите внимание на использование для свойств модификатора override. Программа принимает размер стороны в качестве входных данных и вычисляет площади квадрата и куба. Она также принимает площадь в качестве входных данных и вычисляет значение стороны квадрата и куба.
abstract class Shape
{
public abstract double Area
{
get;
set;
}
}
class Square : Shape
{
public double side;
public Square(double s) //constructor
{
side = s;
}
public override double Area
{
get
{
return side * side;
}
set
{
side = System.Math.Sqrt(value);
}
}
}
class Cube : Shape
{
public double side;
public Cube(double s)
{
side = s;
}
public override double Area
{
get
{
return 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
*/
См. также
Ссылки
Свойства (Руководство по программированию в C#)
Свойства интерфейса (Руководство по программированию на C#)
Автоматически реализуемые свойства (Руководство по программированию на C#)