C#. Свойства. Аксессоры get, set. Примеры классов, содержащих свойства
Содержание
- 1. Понятие свойства. Общая форма. Аксессоры get, set
- 2. Преимущества использования свойств в классах
- 3. Пример свойства, реализующего чтение/запись переменной типа int
- 4. Как влияют модификаторы доступа к элементам класса (private, public) на доступ к свойству?
- 5. Пример свойства, которое реализует доступ к внутренней переменной, которая есть массивом чисел типа double
- 6. Пример свойства, которое реализует доступ к структурной переменной (struct)
- 7. Пример свойства, которое реализует доступ к объекту класса
- 8. Определяют ли свойства место в памяти для полей класса?
- Связанные темы
Поиск на других ресурсах:
1. Понятие свойства. Общая форма. Аксессоры get, set
Свойство – это специальное поле класса, содержащее программный код доступа к внутренним переменным (полям) класса или вычисления некоторого значения. Свойства обеспечивают удобный и рациональный путь доступа к внутренней переменной в классе.
Общая форма объявления свойства в классе
type PropName { get { // код для чтения внутреннего поля (переменной) // ... } set { // код для записи значения во внутреннее поле (переменную) // ... } }
где
- type – тип данных возвращаемый свойством;
- PropName – имя свойства. По этому имени идет обращение к свойству;
- get – аксессор, который используется для чтения значения из внутреннего поля класса;
- set – аксессор, используемый для записи значения во внутреннее поле класса. Аксессор set получает неявный параметр value, содержащий значение, которое присваивается свойству.
Если имя свойства встречается в правой части оператора присваивания или в выражении
variable = obj.PropName; // get
тогда вызывается get. Здесь obj – имя экземпляра класса, в котором объявлено свойство PropName.
Если имя свойства встречается в левой части оператора присваивания
obj.PropName = expression; // set
тогда вызывается аксессор set. Здесь obj – имя экземпляра класса, в котором объявлено свойство PropName.
⇑
2. Преимущества использования свойств в классах
Использование свойств в классах дает следующие преимущества:
- обеспечивается более рациональный и естественной доступ к внутренним переменным класса;
- в коде аксессоров можно реализовывать разного рода проверки на допустимость значений внутренних переменных класса;
- гибкость в правах доступа к внутренней переменной: отсутствие аксесора set позволяет реализовать доступ «только для чтения» для внутренних данных класса. Это, в свою очередь, делает невозможным случайное изменение этих данных.
⇑
3. Пример свойства, реализующего чтение/запись переменной типа int
В примере демонстрируется простой случай доступа к свойству в классе. Объявляется класс с именем IntNumber в котором реализованы:
- внутренняя скрытая (private) переменная типа int с именем d;
- конструктор с одним параметром, который инициализирует переменную d;
- свойство с именем Number. Это свойство содержит аксессоры get и set;
- метод Display для вывода значения скрытой (private) переменной d.
Текст класса IntNumber и его использование в функции main() следующий (приложение типа Console Application)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { // простейший пример класса, в котором используются свойства class IntNumber { private int d; // конструктор public IntNumber(int _d) { d = _d; } // объявление свойства с именем Number public int Number { // чтение поля d get { return d; } // запись в поле (переменную) d set { d = value; } } // вывод поля d на экран public void Display() { Console.WriteLine("d = {0}", d); } } class Program { static void Main(string[] args) { // объявить экземпляр с именем number класса IntNumber IntNumber number = new IntNumber(5); // вывести значение внутренней переменной d number.Display(); // d = 5 // изменить значение d через свойство Number.set number.Number = 25; number.Display(); // d = 25 // использовать свойство Number.get для чтения d int t; t = number.Number; // t = 25 Console.WriteLine("t = {0}", t); } } }
Результат выполнения программы
d = 5 d = 25 t = 25 Press any key to continue . . .
⇑
4. Как влияют модификаторы доступа к элементам класса (private, public) на доступ к свойству?
Чтобы использовать свойство, оно должно быть объявлено с модификатором доступа public. Если свойство объявить с модификатором доступа private, то это свойство будет недоступно. В результате, при попытке доступа к свойству, компилятор выдаст сообщение об ошибке
ClassName.PropName is inaccessible due to its protection level
где PropName – имя private-свойства, объявленного в классе ClassName.
⇑
5. Пример свойства, которое реализует доступ к внутренней переменной, которая есть массивом чисел типа double
В примере объявляется класс ArrayDouble, реализующий массив вещественных чисел. В классе объявляются:
- внутренняя скрытая (private) переменная A, которая есть массивом чисел типа double;
- два конструктора класса;
- индексатор, который возвращает элемент массива по заданному индексу;
- свойство Sum, которое определяет аксессоры get и set.
Текст класса ArrayDouble и его использование в методе main(), следующий
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { // массив типа double class ArrayDouble { double[] A; // массив чисел типа double // конструкторы класса public ArrayDouble(int size) { // выделить память под массив A = new double[size]; // заполнить массив нулями for (int i = 0; i < size; i++) A[i] = 0.0; } public ArrayDouble(double[] _A) { // выделить память для массива A = new double[_A.Length]; // скопировать один массив в другой for (int i = 0; i < _A.Length; i++) A[i] = _A[i]; } // индексатор public double this[int index] { get { if ((index >= 0) && (index < A.Length)) return A[index]; else return 0.0; } } // свойство Sum: // get - определяет сумму элементов массива // set - распределяет элементы в массиве равными значениями, // сумма элементов равна value public double Sum { get { // вычисление суммы элементов double s = 0; for (int i = 0; i < A.Length; i++) s += A[i]; return s; } set { // равномерное распределение элементов массива A значениями value double v = value/A.Length; for (int i = 0; i < A.Length; i++) A[i] = v; } } } class Program { static void Main(string[] args) { double[] X = { 1.0, 2.5, 2.0, 4.5, 0.0 }; // массив ArrayDouble ad = new ArrayDouble(X); // создать экземпляр класса ArrayDouble double sum; // сумма элементов sum = ad.Sum; Console.WriteLine("sum = {0}", sum); // заполнить массив в экземпляре ad значениями 1.0 ad.Sum = 1.0 * X.Length; // проверка double t; t = ad[2]; // t = 1.0 Console.WriteLine("t = {0}", t); } } }
В классе ArrayDouble реализовано свойство Sum. Это свойство определяет два аксессора get и set. С целью демонстрации аксессор get реализует вычисление суммы элементов массива A
... public double Sum { get { // вычисление суммы элементов double s = 0; for (int i = 0; i < A.Length; i++) s += A[i]; return s; } ... } ...
Также с помощью аксессора set в каждый элемент массива A заносится значение value/A.length
... set { // равномерное распределение элементов массива A значением value double v = value/A.Length; for (int i = 0; i < A.Length; i++) A[i] = v; } ...
Вывод: в аксессорах get, set можно задавать дополнительные операции вычисления над данными класса. Необязательно должно возвращаться значение некоторого поля в классе.
Результат работы программы
sum = 10 t = 1 Press any key to continue . . .
⇑
6. Пример свойства, которое реализует доступ к структурной переменной (struct)
В примере демонстрируется доступ к структуре типа Fracion с помощью свойств. Свойства объявляются в классе Complex, реализующем комплексное число. Класс Complex декларирует следующие элементы:
- внутренние скрытые (private) переменные real, imag. Эти переменные (поля) соответствуют действительной и мнимой части комплексного числа;
- свойство Real для чтения/записи значения поля real;
- свойство Imag для чтения/записи значения поля imag;
- свойство RealD, представляющее значение поля real в виде вещественного числа типа double. Это свойство предназначено только для чтения (get), аксесор set отсутствует в свойстве;
- свойство ImagD, представляющее значение поля imag в виде вещественного числа типа double. Это свойство предназначено только для чтения (get);
- свойство Abs, вычисляющее модуль комплексного числа. Это свойство предназначено только для чтения.
Текст программы для приложения типа Console Application следующий
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { // структура, реализующая дробь struct Fraction { public int num; // числитель public int denom; // знаменатель } // клас, реализующий комплексное число class Complex { private Fraction real; // действительная часть комплексного числа в виде дроби private Fraction imag; // мнимая часть комплексного числа в виде дроби // конструкторы public Complex(int _real, int _imag) { real.num = _real; real.denom = 1; imag.num = _imag; imag.denom = 1; } public Complex(Fraction _real, Fraction _imag) { real = _real; imag = _imag; } // свойство, соответствующее действительной части комплексного числа public Fraction Real { get { return real; } set { real = value; } } // свойство, соответствующее мнимой части комплексного числа public Fraction Imag { get { return imag; } set { imag = value; } } // свойство, возвращающее действительную часть комплексного числа // в виде типа double public double RealD { get { return (double)real.num / (double)real.denom; } } // свойство, возвращающее мнимую часть комплексного числа // в виде типа double public double ImagD { get { return (double)imag.num / (double)imag.denom; } } // свойство, возвращающее модуль комплексного числа public double Abs { get { double t,r,i; r = real.num / (double)real.denom; i = imag.num / (double)imag.denom; t = Math.Sqrt(r * r + i * i); return t; } } } class Program { static void Main(string[] args) { Fraction r = new Fraction(); Fraction i = new Fraction(); r.num = 3; r.denom = 1; i.num = 4; i.denom = 1; Complex cm = new Complex(r, i); // создать экземпляр класса Complex // демонстрация работы свойств класса Complex // свойство Abs double abs = cm.Abs; // взять модуль, abs = 5 Console.WriteLine("Abs = {0}", abs); // свойства RealD, RealI double rd, id; rd = cm.RealD; // rd = 3/1 = 3.0 id = cm.ImagD; // id = 4/1 = 4.0 Console.WriteLine("rd = {0}", rd); // свойство Real Fraction R = new Fraction(); R = cm.Real; // R = { 3, 1 } Console.Write("R.num = {0}, ", R.num); Console.WriteLine("R.denom = {0}", R.denom); } } }
Результат работы программы
Abs = 5 rd = 3 R.num = 3, R.denom = 1 Press any key to continue . . .
⇑
7. Пример свойства, которое реализует доступ к объекту класса
В примере демонстрируется доступ к объекту класса с помощью свойства.
Объявляется класс Point, реализуючий точку на координатной плоскости. В классе объявляются:
- две внутренние скрытые (private) переменные x, y которые есть координатами точки;
- два конструктора;
- свойства X, Y. Эти свойства с помощью аксессоров get, set реализуют доступ к скрытым переменным x, y.
Также объявляется класс Line, который реализует линию состоящую из двух точек типа Point. В классе реализованы:
- скрытые (private) внутренние переменные p1, p2 типа Point. Это точки концов отрезка;
- свойства P1, P2 реализующие доступ к внутренним переменным p1, p2. В этих свойствах продемонстрирован возврат объекта класса типа Point;
- свойство Length, определяющее длину линии. Это свойство содержит только один аксессор get. Аксессор set отсутствует.
Текст демонстрационной программы, созданной по шаблону Console Application следующий
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ConsoleApp7 { // класс, реализующий линию class Point { private float x; private float y; // конструкторы public Point() { x = y = 0f; } public Point(float _x, float _y) { x = _x; y = _y; } // свойства public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } } // класс, реализующий линию class Line { // внутренние данные - точки линии, объекты класса Point private Point p1; private Point p2; // конструктор public Line(Point _p1, Point _p2) { p1 = new Point(); p1.X = _p1.X; p1.Y = _p1.Y; p2 = new Point(_p2.X, _p2.Y); } // свойства public Point P1 // получить первую точку линии { get { return p1; } set { p1 = value; } } public Point P2 // получить вторую точку линии { get { return p2; } set { p2 = value; } } // свойство, определяющее длину линии, // содержит только один аксессор get public double Length { get { double len; len = Math.Sqrt(p1.X * p1.X + p2.Y * p2.Y); return len; } } } class Program { static void Main(string[] args) { // доступ к объекту класса с помощью свойства // создать экземпляры класса Point p1 = new Point(2, 4); Point p2 = new Point(6, 8); Line line = new Line(p1, p2); // демонстрация свойств P1, P2 класса Line Point p3, p4; p3 = line.P1; // аксессор get p4 = line.P2; float x, y; x = p3.X; // x = 2 y = p3.Y; // y = 4 Console.WriteLine("x = {0}, y = {1}", x, y); p3.X = -3; p3.Y = -1; line.P1 = p3; // аксессор set Console.WriteLine("x = {0}, y = {1}", line.P1.X, line.P1.Y); // вывести длину линии с помощью свойства Length double length; length = line.Length; Console.WriteLine("Length = {0}", length); } } }
Как видно из вышеприведенного кода, в классе Line реализованы два свойства, которые осуществляют доступ к объекту класса Point
... // свойства public Point P1 // получить первую точку линии { get { return p1; } set { p1 = value; } } public Point P2 // получить вторую точку линии { get { return p2; } set { p2 = value; } } ...
Результат выполнения программы
x = 2, y = 4 x = -3, y = -1 Length = 8.54400374531753 Press any key to continue . . .
⇑
8. Определяют ли свойства место в памяти для полей класса?
Нет, не определяют. Свойства руководят доступом к полям. Само свойство не представляет поле (член данных) класса. Поле должно быть определено в классе независимо от свойства.
⇑
Связанные темы
⇑