Определение классов в программе
От использования готовых классов .NET Framework мы переходим к определению собственных классов в программе. Код класса можно разместить в отдельном файле при помощи команды Project > Add Class, как в VB6, или же просто ввести его в нужном модуле — например, в стартовом модуле, содержащем точку входа в консольное приложение.
В процессе тестирования мы предпочитаем связывать каждый класс с процедурой Sub Main, в которой он используется. Таким образом, код классов не оформляется в виде отдельных модулей классов, а выделяется в программный модуль с отдельной процедурой Sub Main, предназначенной для их тестирования. Если вы последуете нашему примеру, учтите, что код, определяемый на уровне модуля, доступен везде, где доступен сам модуль. Таким образом, мы создаем некий аналог глобальных переменных и функций VB .NET — со всеми опасностями, присущими глобальным данным.
VB .NET не смотрит на то, сколько классов определяется в одном файле. В большинстве классов определяются один или два конструктора, свойства для чтения и изменения состояния объекта, а также методы для выполняемых действий. Для примера возьмем простейший класс Empl oyee с двумя полями (имя и зарплата) и небольшую тестовую программу. В классе определяются два свойства, доступных только для чтения; эти свойства возвращают значения полей. Методы в этом классе отсутствуют:
1 Module EmployeeTestl
2 Sub Main()
3 Dim Tom As New Employee("Tom". 100000)
4 Console.WriteLine(Tom.TheName & "salary is " & Tom.Salary)
5 Console. ReadLine()
6 End Sub
7 ' Определение класса
8 Public Class Employee
9 Private m_Name As String
10 Private m_Salary As Decimal
11 Public Sub New(ByVa1 sName As String.ByVal curSalary As Decimal)
12 m_Name = Sname
13 m_Salary = curSalary
14 End Sub
15 Public Readonly Property TheName()As String
16 Get
17 Return m_Name
18 End Get
19 End Property
20 Public Readonly Property Salary() As Decimal
21 .Get .
22 Return m_Salary
23 End Get
24 End Property
25 End Class
26 End Module
В строках 2—6 определяется процедура Sub Main, используемая компилятором в качестве точки входа. Если эта процедура выбрана в качестве стартового объекта (это происходит по умолчанию, но вообще стартовый объект выбирается в диалоговом окне Project Properties), она отвечает за создание исходных экземпляров. Далее созданные объекты обычно создают другие объекты в ответ на получение ими сообщений. Конечно, в нашей простой программе ничего такого не происходит.
Непосредственное создание объекта происходит в строке 3, играющей ключевую роль в процессе тестирования программы. В этой строке при создании нового объекта Empl oyee методу New передаются два параметра — имя и начальная зарплата. В строке 4 мы выводим значения свойств TheName и Salагу, чтобы убедиться в том, что исходное состояние созданного объекта было задано верно.
Класс Empl oyee определяется в строках 8-25. Как упоминалось выше, для удобства тестирования код класса определяется в исходном модуле, хотя мы с таким же успехом могли воспользоваться командой Project > Add Class и выделить его в отдельный файл.
Давайте внимательно рассмотрим каждую строку в определении класса. В строке 8 ключевое слово Publiс является атрибутом уровня доступа и определяет, кому разрешено создавать экземпляры этого класса. В нашем примере класс объявлен открытым, поэтому теоретически любой желающий сможет создавать его экземпляры после компиляции — для этого в программу достаточно включить ссылку на сборку, содержащую этот класс (сборки рассматриваются в главе 13). Чтобы класс мог использоваться только в рамках нашего проекта и оставался недоступным для внешних программ, ключевое слово Public следует заменить ключевым словом Friend.
В строках 9 и 10 определяются закрытые поля для хранения информации о состоянии объекта. В очередной раз напомним, что переменные всегда должны объявляться закрытыми (Private). В своих определениях классов и модулей мы всегда начинаем имена полей с префикса m_ или m.
В строках 11-14 определяется конструктор, предназначенный для создания экземпляров класса. Конструктор задает значения закрытых полей экземпляра в соответствии со значениями полученных параметров.
В строках 15-19 и 20-24 определяются два открытых свойства, доступных только для чтения. Они предназначены для получения информации о текущем состоянии объекта. В приведенном примере использовано ключевое слово Return, однако с таким же успехом можно было применить старый синтаксис с присваиванием имени свойства:
Get
TheName = m_Name
End Get
Впрочем, даже в этой форме синтаксис процедуры свойства несколько изменился по сравнению с VB6 — исчезли старые конструкции Property Get/Property Set.
Следующая версия программы показывает, как сделать свойство Salary доступным для чтения и записи. Для этого достаточно удалить ключевое слово Readonly и добавить небольшой фрагмент:
Public Property Salary()As Decimal Get
Return m_Salary End Get Set(ByVal Value As Decimal)
m_Salary = Value
End Set
End Property
В этом фрагменте прежде всего следует обратить внимание на чтение нового значения свойства с применением ключевого слова Value. Иначе говоря, когда в программе встречается строка вида Tom.Salary = 125000, параметру Value автоматически присваивается значение 125 000.
Иногда встречаются ситуации, когда свойство требуется объявить доступным только для записи. Для этого перед именем свойства ставится ключевое слово WriteOnly, a затем определяется секция Set без секции Get.
Допустим, мы решили объявить свойство Salary доступным только для чтения и включить в класс метод для повышения зарплаты. Метод объявляется как обычная процедура или функция. В нашем примере метод не возвращает значения, поэтому выбор стоит остановить на процедуре:
Public Sub RaiseSalary(ByVal Percent As Decimal)
m_Salary =(1 + Percent) * m_salary
End Sub
Члены класса объявляются с модификаторами Public, Private или Friend. Ключевое слово Pri vate означает, что член класса используется только внутри класса.
В классах иногда объявляются закрытые конструкторы. «Какая польза от закрытого конструктора?» — спросите вы. Конструктор объявляется закрытым в том случае, если он вызывается только самим классом исходя из логики его работы.
По умолчанию в VB .NET для классов и их членов используется уровень доступа Friend (доступ разрешается только из текущей программы). Впрочем, пропускать атрибуты уровня доступа при объявлении класса не рекомендуется — особенно если учесть, что уровень доступа, принятый по умолчанию, не является минимальным.