Учебное пособие (1077022), страница 7
Текст из файла (страница 7)
Оно отсутствует в языках C++ иJava в явном виде, вернее реализуется в этих языках с помощью данных иметодов.Если бы в языке С# не было свойств, также как и в C++ и Java, томожно было бы написать следующий код://объявление переменнойprivate int i;//метод чтенияpublic int get_i() { return this.i; }//метод записиpublic void set_i(int value) { this.i = value; }Смысл этого кода вполне понятен – к закрытой переменной можнообратиться на чтение и запись с помощью открытых методов. Но в языкеС# для реализации такой задачи существует специальный вид конструкции– свойство.Пример объявления простого свойства://private-значение, которое хранит данные для свойстваprivate int _property1 = 0;//объявление свойстваpublic int property1{//возвращаемое значениеget { return _property1; }//установка значения, value - ключевое словоset { _property1 = value; }}Переменная _property1 является закрытой (private) и содержит данныедля свойства.
Такую переменную принято называть опорной переменнойсвойства. Как правило, опорные переменные всегда имеют областьвидимости private или protected, чтобы к ним не было внешнего доступа.Дляопорныхпеременныхпринятоследующеесоглашениепонаименованию – опорная переменная имеет то же имя что и свойство, ноперед ним ставится подчеркивание «_».52Далее следует объявление свойства «public int property1». Внешне оноочень похоже на объявление переменной, но после него ставятся фигурныескобки и указываются секции get и set, которые принято называтьаксессорами (accessors), поскольку они обеспечивают доступ к свойству.Get-аксессор (аксессор чтения) – метод, который вызывается причтении значения свойства. Как правило, он содержит конструкцию return,возвращающую значение опорной переменной.
Конечно, в get-аксессореможет выполняться и более сложный код.Тип возвращаемого значения get-аксессора, который не задается вкоде в явном виде, совпадает с типом свойства.Set-аксессор (аксессор записи) является методом, который вызываетсяпри присвоении значения свойству. Как правило, он содержит операторприсваивания значения опорной переменной «_property1 = value». В этомслучае ключевое слово value обозначает то выражение, которое стоит вправой части от оператора присваивания.Тип возвращаемого значения set-аксессора, который не задается вкоде в явном виде, это тип void.Объявленное свойство ведет себя как переменная, которой можноприсвоить или прочитать значение.Пример использования свойства://Создание объекта класса для работы со свойствомBaseClass bc = new BaseClass(333);//Присвоение значения свойству (обращение к set-аксессору)bc.property1 = 334;//Чтение значения свойства (обращение к get-аксессору)int temp = bc.property1;Таким образом, свойство «кажется» обычной переменной, которойможно присвоить или прочитать значение.
Однако при этом происходитобращение к соответствующим аксессорам свойства.Области видимости аксессоров по умолчанию совпадают с областьювидимости свойства, как правило, используется область видимости public.53Однако для каждого аксессора можно указать свою область видимости,например:public int property1{get { return _property1; }private set { _property1 = value; }}В этом случае область видимости аксессора чтения совпадает собластью видимости свойства (public), а область видимости аксессоразаписи ограничена текущим классом (private). То есть прочитать значениетакого свойства можно из любого места программы, а присвоить – тольков текущем классе.Рассмотренный код аксессоров используется очень часто.
Чтобыоблегчить написание кода, в языке C# для таких «стандартных» свойствпринята упрощенная форма синтаксиса, называемая автоопределяемымсвойством:public string property2 { get; set; }Такая упрощенная форма синтаксиса эквивалентна следующемуописанию:private string _property2;public string property2{get { return _property2; }set { _property2= value; }}В автоопределяемом свойстве опорная переменная «_property2» висходном коде явно не задается, а автоматически генерируется на этапекомпиляции и позволяет хранить значение свойства на этапе выполненияпрограммы.Для аксессоров как автоопределяемого свойства, так и обычногосвойства, можно явно указывать собственные области видимости:public float property3 { get; private set; }54Свойство может содержать только один из аксессоров. Например,можно создавать вычисляемые свойства, которые используются длявычисления значений и базируются на опорных переменных другихсвойств:/// <summary>/// Вычисляемое свойство/// </summary>public int property1mul2{get { return property1 * 2; }}Вычисляемые свойства, как правило, содержат только аксессорычтения.
Следует отметить, что для данного свойства также задан XMLкомментарий.Для программистов, работающих на C++ или Java, может быть несовсем понятно, почему в языке C# свойствам придается такое важноезначение. В языке C# в классах вообще не принято использовать publicпеременные, вместо них употребляются автоопределяемые свойства.СвойствапозволяютпридаватьпрограммамнаязыкеC#дополнительную гибкость, особенно при модификации кода. Например,если изменились правила вычисления какой-либо переменной (допустим,нужно возвращать значение переменной.
умноженной на 2), то можномодифицировать get-аксессор не внося изменений в вызывающий код.Если же при присвоении переменной нужно производить дополнительныйконтроль (допустим, целочисленной переменной можно присваиватьзначения только от 1 до 1000), его можно поместить в set-аксессор (еслиусловие не выполняется, то генерируется исключение) не внося измененийв вызывающий код.Поэтому в языке C# принято объявлять public-переменные класса какавтоопределяемые свойства, а при необходимости свойство может бытьпереписано в полной форме с расширением кода аксессоров.В версии C# 6 появились новые возможности работы со свойствами.55Приобъявлениисвойствавозможнаегонепосредственнаяинициализация:public string String1 { get; set; } = "строка 1";Возможно объявление автоопределяемых свойств, предназначенныхтолько для чтения.
Такие свойства могут быть инициализированы вконструкторе класса или непосредственно при объявлении свойства.public int Int1 { get; } = 333;public int Int2 { get; }/// <summary>/// Конструктор класса/// </summary>public PropertyExample(){this.Int2 = 45;}Попытка изменить такое свойство, например, в методе классаприводит к ошибке:public void Method1(){//Ошибкаthis.Int1 = 123;}Компиляторвыдаетследующийтекстошибки:«Невозможноприсвоить значение свойству или индексатору "PropertyExample.Int1" —доступ только для чтения».4.1.4 Объявление деструкторовКлассы C# могут содержать деструкторы, которые объявляютсяаналогично деструкторам в языке C++.Пример объявления деструктора:~BaseClass(){Console.WriteLine("\nДеструктор}класса BaseClass");Однако на практике деструкторы используются редко, потому чтоосновной задачей деструкторов в языке C++ является очистка памяти.
А в56среде .NET очистка памяти выполняется автоматически с помощьюсборщика мусора, поэтому надобность в деструкторах практическиотпадает.4.1.5 Объявление статических элементов классаЭлемент класса в языке C# может быть объявлен как статический спомощью ключевого слова static. Это означает, что данный элемент (поледанных, свойство, метод) принадлежит не объекту класса, а классу вцелом, и для работы с такими элементами не нужно создавать объекткласса.Вызовстатическогометодавыполняетсявформате«Имя_класса.имя_метода(параметры)».
Таким образом, для вызова какстатических, так и нестатических методов используется символ «.». Но вслучае статического метода перед символом «.» ставится имя класса, а вслучае нестатического метода перед символом «.» ставится имя объекта.Аналогично создаются и вызываются статические методы в Java, а в языкеС++ вместо точки используется символ удвоенного двоеточия «::».В языке C# весь класс может быть объявлен как статический.
В этомслучае ключевое слово static указывается перед именем класса, а всеэлементы класса должны быть статическими.4.1.6 Конструкция «using static»В версии C# 6 появилась новая разновидность конструкции using –using static, которая позволяет импортировать все методы из статическогокласса.До появления этой конструкции для вычисления квадратного корнянеобходимо было написать следующий код:using System;namespace UsingExample{57class Program{static void Main(string[] args){double number = 4.0;double root = Math.Sqrt(number);}}}Класс Math объявлен в пространстве имен System, котороеподключаетсяспомощьюдирективыusing.Сиспользованиемконструкции Math.Sqrt мы обращаемся к методу Sqrt статического классаMath.В версии C# 6 возможно использование следующей конструкции:using static System.Math;namespace UsingExample{class Program{static void Main(string[] args){double number = 4.0;double root = Sqrt(number);}}}В этом случае в конструкции using указывается, что мы импортируемвсе методы из статического класса Math.
Поэтому к функции Sqrt мыобращаемся так, как будто она объявлена локально в текущем классе.Использовать префикс с именем класса перед функцией для вызовафункции не нужно.4.2 Наследование класса от классаВ языке C# наследовать класс можно только от одного класса. Вданном примере класс ExtendedClass1 наследуется от класса BaseClass:/// <summary>/// Наследуемый класс 1/// </summary>class ExtendedClass1 : BaseClass58{private int i2;private int i3;//Конструкторы//base(pi) - вызов конструктора базового классаpublic ExtendedClass1(int pi, int pi2) : base(pi) { i2 = pi2; }//this(pi, pi2) - вызов другого конструктора этого классаpublic ExtendedClass1(int pi, int pi2, int pi3) : this(pi, pi2){ i3 = pi3; }//////////////////<summary>Метод виртуальный, так как он объявлен в самом базовом классеobjectпоэтому чтобы его переопределить добавлено ключевое словоoverride</summary>public override string ToString(){return "i=" + MethodReturn("1")+ " i2=" + i2.ToString() + " i3=" + i3.ToString();}}Синтаксис наследования в языке C# аналогичен синтаксису языкаC++.















