Гайдар Магдануров
Microsoft Visual Studio 2005
Часть 5. Изменения в языке VB.NET
Наконец-то мы добрались до новшеств в языке
Visual Basic .NET! Конечно, все новинки в среде
разработки и Framework очень важны, возможно, не менее
важны, чем изменения в языке, но все-таки каждому профессиональному программисту
преимущественно использующему Visual Basic, особенно если
разработчика привлек простой и интуитивно понятный синтаксис Visual Basic
(по этому поводу можно вести длинные споры, но это не тема
текущей статьи), то любые изменения в языке важнее каких
бы то ни было изменений в среде разработки.
С выходом Framework 2.0 и
Visual Studio 2005 язык Visual Basic
приобрел множество весьма полезных и долгожданных функций, частично почерпнутых
из других языков входящих в Visual Studio предыдущих
версий. Каждая новая версия языка делает язык более функциональным , но при этом
конструкции становятся компактнее и код более читаемым. Профессиональные
разработчики, которые помнят еще Visual Basic первой
версии увидят преимущества новых конструкций, а новичкам, только начинающим свой
путь программиста можно только позавидовать!
Все. Хватит толочь воду в ступе, пора бы уже перейти к самому
интересному! Если у вас есть возможность сразу же после прочтения этой статьи
запустить Visual Studio и попробовать все, о чем в ней
говорится - это замечательно, но еще лучше, если вы запустите Visual
Studio 2005 прямо сейчас и пройдете материал этой статьи вместе
с этим великолепным помощником программиста!
Я начну с одного из самых захватывающих
новшеств в Visual Basic - поддержка
общих типов
(generic).
Программисты на C++ поймут аналогию с
шаблонами (template), к сожалению такую
аналогию пока еще рано проводить, поскольку общие классы пока есть только в
C# и то не соответствующие шаблонам с C++.
Будем надеяться, что в будущем разработчики языка Visual
Basic порадуют нас и этим. Но пока уже то, что есть
является одним большим шагом вперед!
Общие типы в Visual Basic позволяют о
классы не указывая конкретный тип переменных в момент написания кода класса. Тип
переменной внутри класса определяется в момент использования этого класса.
Приведу пример класса, где использованы общие типы.
Public Class GenericClass(Of VarType)
Private m_Var As VarType
Public Property Var() As VarType
Get
Return m_Var
End Get
Set(ByVal value As VarType)
m_Var = value
End Set
End Property
End Class
Для использования общих типов необходимо
после объявления класса использовать конструкцию (Of SomeName),
где SomeName - любое имя, которое в
дальнейшем будет использовано для объявления типа переменной. И объявление
переменной также надо сопроводить инструкцией Of,
определяющей конкретный тип. Использование этого класса
показано далее.
Dim gen1 As GenericClass(Of Integer) ' переменная типа GenericClass с использованием Integer типа
Dim gen2 As GenericClass(Of String) ' переменная типа GenericClass с использованием String типа
gen1.Var = 2 ' OK
gen2.Var = "Some string" ' OK
gen1.Var = "Another string" ' Ошибка
gen2.Var = 2 ' Ошибка
Перегрузка операторов - одна из наиболее
желаемых и долгожданных возможностей еще до времен Visual Basic .NET!
Наконец-то это желание воплотилось в жизнь. Для начинающих Я
немного расскажу, что это такое. Допустим у нас есть класс, представляющий собою
комплексное число. Хотелось бы выполнять математические операции с этими
классами используя стандартные операторы +, - и т.п. Для
этого-то и необходима перегрузка операторов. Продемонстрирую это на примере.
Public Class ComplexNumber
Private realPart As Double
Private imaginaryPart As Double
Public Property Re() As Double
Get
Return realPart
End Get
Set(ByVal value As Double)
realPart = value
End Set
End Property
Public Property Im() As Double
Get
Return imaginaryPart
End Get
Set(ByVal value As Double)
imaginaryPart = value
End Set
End Property
Public Sub New()
imaginaryPart = 0
realPart = 0
End Sub
Public Sub New(ByVal Re As Double, ByVal Im As Double)
imaginaryPart = Re
realPart = im
End Sub
Public Overloads Shared Operator +(ByVal cn1 As ComplexNumber, _
ByVal cn2 As ComplexNumber) As ComplexNumber
Dim cn3 As New ComplexNumber
cn3.Re = cn1.Re + cn2.Re
cn3.Im = cn1.Im + cn2.Im
Return cn3
End Operator
Public Overloads Shared Operator -(ByVal cn1 As ComplexNumber, _
ByVal cn2 As ComplexNumber) As ComplexNumber
Dim cn3 As New ComplexNumber
cn3.Re = cn1.Re - cn2.Re
cn3.Im = cn1.Im - cn2.Im
Return cn3
End Operator
Public Overloads Shared Operator <>(ByVal cn1 As ComplexNumber, _
ByVal cn2 As ComplexNumber) As Boolean
If cn1.Im <> cn2.Im Or cn2.Im <> cn2.Im Then Return True ' не равны
Return False ' равны
End Operator
Public Overloads Shared Operator =(ByVal cn1 As ComplexNumber, _
ByVal cn2 As ComplexNumber) As Boolean
If cn1.Im = cn2.Im And cn2.Im = cn2.Im Then Return True ' равны
Return False ' не равны
End Operator
End Class
Обратите внимание, что существуют парные
операторы, например неравно <> и равно =.
Если вы перегружаете один оператор, то вам необходимо перегрузить и другой.
Пример использования приведен ниже.
Dim cn1 As New ComplexNumber(1, 1)
Dim cn2 As New ComplexNumber(2, 2)
Dim cn3 As New ComplexNumber
cn3 = cn1 + cn2
Debug.Print(cn3.Re.ToString() + " + i" + cn3.Im.ToString())
cn1.Im = 2
cn1.Re = 2
If cn1 = cn2 Then
Debug.Print("CN1 equals CN2")
Else
Debug.Print("CN1 NOT equals CN2")
End If
Вывод этой простой программы:
Новое ключевое слово Using
позволяет "забыть" о вызове Dispose для
очистки занимаемой объектом памяти. Например, мы создаем некоторый объект типа
MyObject (реализующий интерфейс IDisposable),
а после использования освобождаем память вызывая метод Dispose.
Dim myObj As New MyObject()
' Делаем что-нибудь
myObj.Dispose()
Эту же операцию можно провести с
использованием ключевого слова Using:
Using myObj As New MyObject()
' Делаем что-нибудь
End Using
На первый взгляд ничего удобного и полезного,
но, лишь на первый взгляд. На самом деле приведенная конструкция с
использованием Using аналогична следующему коду:
Dim myObj As New MyObject()
Try
' Делаем что-нибудь "опасное", но не требующее перехвата ошибок Catch
Finally
myObj.Dispose()
End Try
Думаю, теперь преимущества использования Using
очевидны. Если нет, то продолжайте писать лишние строки кода
забывая время от времени вызывать метод Dispose.
Это ключевое слово также пришло из C
подобных языков в Visual Basic.
Continue позволяет пропустить часть инструкций в
циклах For, While и Do.
Например:
Dim i As Integer
For i = 0 To 10
If (i Mod 2) = 0 Then Continue For
Debug.Print(i.ToString())
Next
Вывод этой программы:
При этом ключевое слово можно использовать и во вложенных
циклах, например если внутри цикла For находится цикл
While, то можно пропустить итерацию как
While, так и For отдельно
указав Continue While или Continue
For, соответственно.
Оператор IsNot предназначен для
проверки на идентичность ссылок на объект. Вместо IsNot
можно использовать имеющийся ранее оператор Is,
поэтому вы можете выбрать какой из операторов использовать в зависимости от
ваших собственных соображений об удобстве. Эти операторы эквивалентны равно = и
неравно <> для значений переменных.
Часто, эти операторы приходится использовать при работа с
элементами управления Windows Forms или собственными
объектами. Например нам нужно проверить ссылаются ли переменные
a и b на один и тот же
объект, эту задачу можно решить двумя способами, приведенными ниже.
If a Is b Then Debug.Print("A references to the same object as B")
If Not (a IsNot b) Then Debug.Print("A references to the same object as B")
Выбор оператора зависит от того, что удобнее лично вам при использовании
конструкции If... Then.. Else - писать код отработки
равенства в Then или Else.
Оператор позволяет приводить тип переменной не выбрасывая при этом исключения
в случае неудачи. Сравним варианты использования TryCast
и CType на примере:
Private Sub TryCastUse(ByVal obj As Object)
Dim myObj As MyObject
myObj = TryCast(obj, MyObject)
If obj IsNot Nothing Then
' что-нибудь делаем
End If
End Sub
Private Sub CastUse(ByVal obj As Object)
Dim myObj As MyObject
If TypeOf (obj) Is MyObject Then
myObj = CType(obj, MyObject)
' что-нибдуь делаем
End If
End Sub
Два разных способа, богатство выбора и все на ваш собственный вкус!
Точного и понятного перевода названию
Custom Events я придумать не смог. Надеюсь, что мой читатель поможет мне
в этом. Пока же будем использовать англоязычный термин Custom
Events.
Custom Events позволяют контролировать процесс добавления, удаления и
выполнения обработчиков событий. Рассмотрим этот процесс на примере. Создадим
класс CustomEvents, содержащий два события
MyCustomEvent и MyUsualEvent.
MyCustomEvent создается с использованием синтаксиса для
Custom Events.
Public Class CustomEvents
Private myEvent As eventhandler
' "Обычное" событие
Public Event MyUsualEvent()
Public Custom Event MyCustomEvent As EventHandler
AddHandler(ByVal value As EventHandler)
' добавление обработчика
myEvent = CType(System.Delegate.Combine(myEvent, value), EventHandler)
Debug.Print("Handler Added: " + value.Method.ToString())
End AddHandler
RemoveHandler(ByVal value As EventHandler)
' удаление обработчика
myEvent = CType(System.Delegate.Remove(myEvent, value), EventHandler)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As System.EventArgs)
' вызов собтия
If myEvent IsNot Nothing Then myEvent(sender, e)
End RaiseEvent
End Event
Public Sub RaiseMeCustom()
RaiseEvent MyCustomEvent(Nothing, Nothing)
End Sub
Public Sub RaiseMeUsual()
RaiseEvent MyUsualEvent()
End Sub
End Class
Напишем простейшую демонстрационную программу:
Private WithEvents ce As New CustomEvents
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
ce.RaiseMeCustom()
ce.RaiseMeUsual()
End Sub
Private Sub ce_MyCustomEvent1(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles ce.MyCustomEvent
' Делаем что-нибудь здесь
Debug.Print("1c")
End Sub
Private Sub ce_MyCustomEvent2(ByVal sender As Object, _
ByVal e As System.EventArgs) Handles ce.MyCustomEvent
' Делаем что-нибудь и тут
Debug.Print("2c")
End Sub
Private Sub ce_MyUsualEvent1() Handles ce.MyUsualEvent
Debug.Print("1u")
End Sub
Private Sub ce_MyUsualEvent2() Handles ce.MyUsualEvent
Debug.Print("2u")
End Sub
И рассмотрим вывод приведенной выше программы:
Handler Added: Void ce_MyCustomEvent2(System.Object, System.EventArgs)
Handler Added: Void ce_MyCustomEvent1(System.Object, System.EventArgs)
2c
1c
2u
1u
Как видно из вывода программы, мы можем контролировать
процесс добавления обработчиков событий и проводить некоторый "ценз", не говоря
уже о том, что раздел RaiseEvent для события
MyCustomEvent нашего класса, позволяет контролировать
процесс вызова обработчиков и производить дополнительные операции по подготовке/изменению
данных. В нашем примере мы просто добавляем обработчики и выполняем их по
очереди, но это лишь пример, в реальной практике вы ограничены лишь фантазией.
Изменения затронули и свойства классов. Отныне существует
возможность изменять модификаторы доступа к Get и
Set блокам. Например, если необходимо сделать
Get доступным "извне", а Set
недоступным, то можно изменить модификатор доступа только лишь свойства
Set.
Public Class PropClass
Private myInt As Integer
Public Property IntValue() As Integer
Get
Return myInt
End Get
Private Set(ByVal value As Integer)
myInt = value
End Set
End Property
Public Sub Test()
Me.IntValue = 2
End Sub
End Class
Пример использования:
Dim p As New PropClass
p.Test()
p.IntValue = 3 ' ошибка
В Visual Basic.NET версии 2005
вернулся такой знакомый разработчикам синтаксис MyForm.Show().
Внимательный читатель заметил, что в объекте My (см.
предыдущую статью цикла, посвященную My) используются
экземпляры объектов форм по умолчанию.
Да, действительно, в момент запуска приложения создаются
экземпляры объектов форм и теперь можно обращаться к форме используя ее имя, не
создавая переменной соответствующего типа. Например, ранее, для того, чтобы
показать форму приходилось писать:
Dim myForm as SimpleForm
myForm = New SimpleForm()
myForm.Show()
И работать с формой используя ссылку
myForm. Теперь же можно показать форму так же, как это было в старом
добром VB6 и более ранних версиях
VB:
Единственное пока существующее ограничение на использование
экземпляров по умолчанию - это обращение класса к самому себе. То есть внутри
класса формы SimpleForm необходимо ссылаться на
внутренние свойства и методы этого класса как, например,
Me.Text, а не как SimpleForm.Text.
На этом я завершаю знакомство с новинками, которые принесло
нам появление Visual Studio 2005. Конечно же, я не
рассказал абсолютно обо всех новшествах, которые, кстати, могут быть дополнены в
финальной версии Visual Studio (пока же мы имеем
только Beta версию), но
постарался охватить наиболее значимые и основные новшества. Надеюсь, что этот
обзор в пяти частях озаглавленный
Microsoft Visual Studio 2005 поможет вам быстро освоиться в новой среде
разработки.
Вполне вероятно, что я упустил что-то полезное в своих
статьях, о чем прошу мне сообщить по электронной почте
gaidar@vbstreets.ru.
Я приветствую комментарии и дополнения!
Желаю успехов в освоении Framework 2
и Visual Studio 2005!
Ваш Гайдар Магдануров