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() для виведення значення прихованої змінної 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; // 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)
У прикладі демонструється доступ до структури типу Fraction з допомогою властивостей. Властивості оголошуються в класі 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. Чи визначають властивості місце в пам’яті для полів класу?
Ні, не визначають. Властивості керують доступом до полів. Сама властивість не представляє поле (член даних) класу. Поле повинно бути визначене в класі незалежно від властивості.
⇑
Зв’язані теми
⇑