Дата публикации статьи: 04.01.2005 23:14

Гайдар Магдануров
Microsoft Visual Studio 2005
Часть 5. Изменения в языке VB.NET

  • Введение
  • Общие классы
  • Перегрузка операторов
  • Ключевое слово Using
  • Ключевое слово Continue
  • Оператор IsNot
  • Оператор TryCast
  • Custom Events
  • Новые возможности Property
  • Экземпляры по умолчанию
  • Заключение
  • Обсудить в форуме
  • Введение

    Наконец-то мы добрались до новшеств в языке 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

    Вывод этой простой программы:

    3 + i3
    CN1 equals CN2
    Ключевое слово Using

    Новое ключевое слово 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.

    Ключевое слово Continue

    Это ключевое слово также пришло из 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

    Вывод этой программы:

    1
    3
    5
    7
    9

    При этом ключевое слово можно использовать и во вложенных циклах, например если внутри цикла For находится цикл While, то можно пропустить итерацию как While, так и For отдельно указав Continue While или Continue For, соответственно.

    Оператор IsNot

    Оператор 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

    Оператор позволяет приводить тип переменной не выбрасывая при этом исключения в случае неудачи. Сравним варианты использования 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.
    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 нашего класса, позволяет контролировать процесс вызова обработчиков и производить дополнительные операции по подготовке/изменению данных. В нашем примере мы просто добавляем обработчики и выполняем их по очереди, но это лишь пример, в реальной практике вы ограничены лишь фантазией.

    Новые возможности Property

    Изменения затронули и свойства классов. Отныне существует возможность изменять модификаторы доступа к 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.Show()

    Единственное пока существующее ограничение на использование экземпляров по умолчанию - это обращение класса к самому себе. То есть внутри класса формы SimpleForm необходимо ссылаться на внутренние свойства и методы этого класса как, например, Me.Text, а не как SimpleForm.Text.

    Заключение

    На этом я завершаю знакомство с новинками, которые принесло нам появление Visual Studio 2005. Конечно же, я не рассказал абсолютно обо всех новшествах, которые, кстати, могут быть дополнены в финальной версии Visual Studio (пока же мы имеем только Beta версию), но постарался охватить наиболее значимые и основные новшества. Надеюсь, что этот обзор в пяти частях озаглавленный Microsoft Visual Studio 2005 поможет вам быстро освоиться в новой среде разработки.
        Вполне вероятно, что я упустил что-то полезное в своих статьях, о чем прошу мне сообщить по электронной почте gaidar@vbstreets.ru. Я приветствую комментарии и дополнения!

    Желаю успехов в освоении Framework 2 и Visual Studio 2005!
    Ваш Гайдар Магдануров