Главная страница Visual 2000 · Общий список статей
Публикации в журнале BYTE/Россия · Публикации на тему MS .NET

А ты готов к Visual Basic.NET?
Советы тем, кто собирается работать с новой версией VB
Часть 1 (окончание)

Андрей Колесов

© Андрей Колесов, 2001
Авторский вариант. Статья была опубликована c незначительной литературной правкой в журнале BYTE/Россия N 1/2001.
Внимание! Статья отражает знание автором предмета на момент ее публикации! Использовалась версия VB.NET beta 1!

Начало Части 1 Продолжение: Часть 2 Часть 3

Совет 1. Сначала перейдите к VB 6.0

Если вы работаете с VB версии 5.0 и ниже, то следует сначала преобразовать программы в проекты VB 6.0 (со всеми вытекающими задачами их доработки), а уже потом перейти к их адаптации для VB.NET.

В начало статьи

Совет 2. Не спешите расставаться с VB 6.0.

Вполне вероятно, что некоторые приложения будет выгоднее развивать и поддерживать в среде VB 6.0 (даже несколько лет!), чем переводить в VB.NET. Не говоря уже о том, преобразование сложных проектов в новую среду будет совсем не мгновенным.

В начало статьи

Совет 3. Особое внимание нужно при копировании фрагментов кода через буфер обмена.

Такой прием часто применяется при работе с повторно используемыми фрагментами кода. Многие разработчики хранят подобные коллекции программ в различных хранилищах (начиная от текстовых файлов и заканчивая хранилищами типа Code Librarian) — перенос данных оттуда часто выполняется именно таким образом. Например, я порой использую подобный прием, когда нужно переписать нужную процедуру из старого VB5-проекта (и даже VB3) в новую программу.

Понятно, что в этом случае никакого автоматического преобразования кода из VB 6.0 в VB.NET не будет выполняться — вся ответственность за это ложится на разработчика.

Замечание. Если вы пользуетесь коллекцией повторно используемого кода, то нужно выполнить ее преобразование в вариант VB.NET. Интересно, Microsoft сама сделает утилиту такого преобразования для хранилища Code Labrarian или оставит эту задачу на откуп независимым разработчикам?

В начало статьи

Совет 4. Внимательно изучите будущие новшества VB.NET

Их учет в своих программах уже сейчас сведет к минимуму будущие исправления, а может быть и вовсе исключит необходимость в них. Приглядитесь к ним внимательнее — большинство рекомендаций сводятся к простому совету "придерживайтесь классических, правильных приемов программирования".

В начало статьи

Совет 5. Максимально выносите логику обработки из модулей форм

Вообще-то, этому совету я рекомендую следовать всегда, вне зависимости от перехода на VB.NET. Например, если у вас есть форма, которая содержит сколь-нибудь сложную логику, то имеет смысл подумать о создании специального Bas-модуля, куда перенести основные процедуры обработки данных. (Обычно процедуры создаются для реализации повторно используемых фрагментов кода, но тут как раз тот случай, когда полезно их применять и для линейного кода.) Причем речь может идти даже о двух-трех операторах из событийных процедур. Что же касается, обычных процедур, то их нужно записывать в Bas-модули однозначно.

Пользу такого выделения логики уже давно поняли программисты, которые работают одновременно с VB и VBA — несмотря на схожесть реализации программного интерфейса в эти двух системах, перенос программ без особых проблем (но все же проблемы есть!) осуществляется только для модулей кода. А формы у них несовместимы. Поэтому бывает проще перерисовать в новой среде, адаптировать в ней минимальный код обработки и подгрузить готовый Bas-модуль.

Аналогичная ситуация будет с конвертацией существующих VB Forms в Windows Forms, а также модификацией Web Forms. Хотя Microsoft обещает максимально упростить такой переход, но очевидно, что стопроцентного автоматического преобразования не будет.

А если говорить о переносе приложений, то имеет смысл в более широком плане подумать о более четком его разделении на интерфейс пользователя и бизнес-логику и выделении последней в виде автономных ActiveX-компонентов. То есть, речь может идти о выделении из единого приложения, соответствующей библиотеки (или библиотек) объектов. Глядишь, какието из них пригодятся и для других программ. VB.NET делает

В начало статьи

Совет 6. Ориентируйтесь на работу с ASP.NET

VB 6.0 поддерживал три типа Internet-приложений, основанных на использовании доступа через браузер: DHTML-приложения, ActiveX-документы и WebClass-приложения. Все три вида этих приложений могут взаимодействовать с технологиями VB.NET.

Первые два типа приложений в VB.NET поддерживаться не будут. Их автоматического обновления для VB.NET не предусматривается. Лучшим вариантом является продолжение их поддержки в VB 6.0, хотя возможно имеет смысл преобразовать ActiveX-документы в пользовательские элементы управления.

WebClass-приложений также не будет, но будет реализован механизм обновления в ASP.NET, правда, с необходимостью внесения ряда изменений вручную. (Мы уже писали ранее, что ASP.NET является фактически объединением существующих технологий ASP и WebClass.)

В начало статьи

Совет 7. Используйте ADO для работы с базами данных

Главной технологией доступа к данным в VB.NET является ADO.NET, которая является дальнейшим развитием существующей версии ADO. Старые средства — DAO и DRO — будут поддерживаться в VB.NET только на уровне кода (с некоторыми модификациями), но соответствующие элементу управления уже нельзя будет использовать.

Таким образом, если ваши приложения применяют элементы управления DAO и RDO, то нужно либо поменять на ADO, либо продолжать работать с ними в VB 6.0.

В начало статьи

Совет 8. Не используйте свойства и методы по умолчанию

У VB всегда была дурная манера выделять одного "любимчика", используемого по умолчанию, из набора свойств или методов объекта. Например, для элемента управления Label код:


lblMyLabel = "Готовься к VB.NET"

сейчас работает, так как Caption является для метки таким свойством по умолчанию. Хотя правильнее бы было написать так:


lblMyLabel.Caption = "Готовься к VB.NET"

Примечание. В VB.NET для метки нужно вместо Caption использовать свойство Text (оно применяется для хранения содержимого в подобных элементах управления).

Если же вы хотите непременно сократить усилия по написанию кода, то можно предложить такой вариант:


Dim obj As Object 
Set obj = frmMain.txtInput.Text 
Msgbox obj  ' напечатается содержимое текстового поля

Вместе с тем, "параметризованные" свойства по-прежнему можно опускать в VB.NET. Например, "полный" код выглядит следующим образом:


Dim rs As ADODB.Recordset rs.Fields("CompanyName").Value = "Micro-soft"

В VB 6.0 последнюю строку можно записать так:


rs("CompanyName") = "Micro-soft"

В VB.NET можно сделать только такое сокращение:


rs("CompanyName").Value = "Micro-soft"

Мы видим, что пропущено "параметризованное" свойство Fields, но простое свойство Value должно быть указано.

В начало статьи

Совет 9. Используйте раннее связывание

Как известно, в VB реализованы две технологии связывания компонентов проекта — ранее и позднее связывание. Рекомендация приоритетного применения первого варианта является общей для разработки приложений (позднее связывание лучше использовать, когда другого выхода нет или этого требуют условия задачи). На практике позднее связывание применяется, когда сначала объявляется переменная типа Object, которая потом во время выполнения принимает значение конкретного класса или элемента управления.

Но нужно иметь в виду, что для автоматического преобразования синтаксиса Upgrade Wizard должен знать точное значение объекта. Например, если, применяя конструкцию позднего связывания, вы напишите:


Dim obj As Object    ' неопределенный объект 
Set obj = Me.Label1 
obj.Caption = "НекийТекст"

то Мастер не произведет обновления последней строки, так он ориентируется на начальное определение объекта. (Точно также как и то, что для этой строки не будет работать интеллектуальная подсказка и проверка синтаксиса при вводе.)

А если вы сразу опишите конкретный тип объекта (раннее связывание):


Dim obj As Label    ' объект Label 
Set obj = Me.Label1 
obj.Caption = "НекийТекст"

то Мастер выполнит обновление последней строки:


obj.Text = "НекийТекст"

В начало статьи

Совет 10. Не пугайтесь изменения синтаксиса процедуры Property

Как известно, процедура Property представляет собой парную конструкцию Get и Put примерно такого вида:


Property Get MyProperty () As Integer
  MyProperty = m_MyProperty
End Property Property Set MyProperty (NewValue As Integer)
  m_MyProperty = NewValue
End Property

Такое разнесение кода очень неудобно, в частности, потому что две конструкции окажутся в разных частях программного модуля. Теперь Property будет реализовано в следующем виде (преобразование выполняется автоматически):


Property MyProperty () As Integer
  Get
    MyProperty = m_MyProperty
  End Get
  Set
    m_MyProperty = Value
  End Set
End Property

В начало статьи

Совет 11. Не используйте прямые ссылки на элементы управления других форм

До сих пор все элементы управления на формах имели фиксированный статус Public. Соответственно, доступ к ним можно было получить из любого места проекта, например, следующим образом:


sTitle = frmSomeForm.txtTitle1.Text

Теперь можно будет обращаться к тем элементам управления, для которых в явном виде указан статус Puclic Shared.

Однако тут нужно отметить, что такой прямой метод доступа к внутренним компонентам формы (не только элементам управления) является не очень хорошим решением. Гораздо изящнее выглядит использование специальных процедур — свойств формы.

Предположим, на некоторой форме имеется набор из пяти кнопок-переключателей (например, для выбора типа отчета), и вам нужно из внешнего BAS-модуля определить их состояние. Можно написать такой код:


For nIndex = 0 To 5
  If frmOptions.optBlock(nIndex) Then
    FormatNumber = nIndex: Exit for
  End if
Next

Но такой вариант не очень хорош. Возможно, позднее вы захотите изменить количество переключателей или их имена. Или заменить блок переключателей списком. Тогда вам нужно будет не только менять код внутри формы, но и во всех местах (!) проекта, где идет обращение к ней. Но такие проблемы легко решить, если создать для формы свойство iNumber и написать для него следующий код:


Public Property Get FormatNumber() As Long
  For nIndex = 0 To 4
    If frmOptions.optBlock(nIndex) Then
      FormatNumber = nIndex: Exit for
    End if
  Next
End Property

Тогда выбор типа отчета будет выполняться строкой:


nMyNumber = frmOptions.FormatNumber

вид которой никак не будет зависеть от внутренней реализации формы. При коррекции этого механизма вам нужно будет менять только процедуру свойства. Например, при замене переключателей списком она будет выглядеть следующим образом:


Public Property Get FormatNumber() As Long
   FormatNumber = lst.ListIndex
End Property

В начало статьи

Совет 12. Готовьтесь к изменению типов целочисленных переменных

До сих пор в VB было два типа целочисленных переменных со знаком — 16-ти (Integer) и 32- разрядные (Long). В VB.NET к ним прибавится 64-разрядный целочисленный тип. Ее появление в условиях полного перехода на 32-разрядную архитектуру и ожидания появления 64- разрядных ПК является вполне естественным и, наверное, нужным для решения практических задач.

Но чтобы немного остудить радость разработчиков, Microsoft решила "бросить ложку дегтя", переименовав традиционные ключевые слова для обозначения целых переменных:


Целые переменный    VB 6.0    VB.NET

16-разрядные        Integer   Short
32-разрядные        Long      Integer
64-разрядные        —        Long

Лично я не вижу смысла такого перестановки имен, кроме объяснения "чтобы жизнь разработчикам медом не казалась". Microsoft это объясняет тем, что "естественной" переменной для современных компьютеров является 32-разрядная величина. Но довод этот весьма слаб — переменная Integer является 16-разрядной на протяжении более сорока последних лет (речь идет не только о VB) совершенно независимо от типа процессоров (от 4-х до 64 разрядных процессоров). Так что, тут можно увидеть лишь вызов устоявшимся традициям.

Разумеется, Upgrade Wizard сделает нужное обновление и вместо


Dim x As Integer
Dim y As Long

запишет в проект VB.NET:


Dim x As Short 
Dim y As Integer

Но все же можно легко представить, что у разработчиков прибавится головной боли, тем более, если учесть, что многим из них будет нужно одновременно работать с разными версиями VB.

Вместе с тем, хотелось обратить внимание, что Microsoft упорно не желает вводить в VB крайне необходимые в работе беззнаковые целые числа. А значит, разработчикам по-прежнему потребуется прибегать к хитрым кодам для выделения, например, байта со знаковым разрядом.

Говоря об использовании разных типов целых переменных надо также отметить следующий момент. (Мы сейчас будет использовать термины Integer и Long в контексте VB 6.0.) Во времена 16-разрядных компьютеров (процессор 286) использование Long приводило не только к увеличению требуемого объема памяти, но также и к снижению скорости выполнения операций (в два раза в обоих случаях). В 32-разрядных системах скорость операция для обоих типов переменных одинакова. Исключение составляют только ранние 32-разрядные модели AMD K5 и K6, которые имели отдельные блоки обработки коротких переменных. (Intel полностью отказалась от 8/16-разрядных блоков при переходе на архитектуру P6.)

В начало статьи

Совет 12a. Готовьтесь к отказу от использования типы данных Currency

В VB.NET не будет поддерживаться тип Currency — вместо него предлагается использовать тип Decimal. Однако, как конкретно применить эту рекомендацию, пока не очень понятно.

Дело в том, что Cuurency — это восьмибайтовая переменная, которая содержит вещественное число в формате с фиксированной десятичной запятой (четыре десятичных знака после запятой). Она специально предназначена для хранения и обработки денежных единиц, хотя некоторые разработчики экономических задач считают точность и диапазон этого типа данных недостаточным для российских условий.

О типе Decimal пока доподлинно известно лишь то, что она занимает 12 байтов и хранит вещественными числа с фиксированной запятой. Но как практически работает арифметика для этих данных и как определяется положение десятичной запятой — не очень понятно. Дело в том, что тип Decimal существует в VB 6.0 лишь "виртуально" — объявить такую переменную нельзя. В справке говорится, что для создания переменной Decimal можно воспользоваться типом Variant и функцией CDec, но результаты реальных тестов расходятся с описанием. Тем не менее в VB.NET обещано появление стандартного встроенного типа Decimal.

В начало статьи

Совет 13. Скорее откажитесь от Variant

Типа данных Variant больше не будет. Программисты, наконец-то, освободятся от "иглы", на которую их пытаются посадить с VB 2.0 (в VB 3.0 этот тип стал использоваться по умолчанию). Заменой ему будет тип Object, которые в VB 6.0 используется только для ссылок на объект. Теперь Object будет применяться также для ссылок на простые переменные, но, кажется, в VB.NET манипуляции с автоматическим преобразованием данных будут сильно ограничены.

Бездумное использование типа данных Variant — одно характерных проявлений "плохого" стиля программирования. И дело тут не в том, что в этом случае нарушаются классические принципы программирования — четкий контроль за типами данных и процедурами их преобразования из одного типа в другой. Просто это является причиной разнообразных проблем при разработке приложений.

На самом деле такой универсальный тип данных действительно нужен для некоторых специальных применений, например, для передачи в процедуру аргументов произвольного типа, но как любое "острое" оружие он требуется очень осторожного обращения. Ведь декларируемое достоинство Variant — автоматическое преобразование данных — несет в себе потенциальную угрозу: непрогнозируемость получаемого результата. (Не говоря уже о снижении эффективности кода из-за преобразование, которые можно легко избежать.) Например, попробуйте "вручную" определить результат работы такой простой конструкции:


Dim a, b 
a = #12/01/2001# 
b = "15,6" + d + 10 + True & True 
Msgbox b

Тут самое удивительное, что подобный абсурдный код допустим с точки зрения синтаксиса VB.

Можно вспомнить, что появление типа Varianl в свое время сопровождалось восторженными приветствиями ИТ-комментаторов ("Наиболее важным нововведением VB 2.0 является "варьируемый" тип данных"). Но сейчас даже Microsoft поняла, что ситуация с преобразованием данных выходит из под контроля и решила вернуться к старым, добрым принципам построения языков программирования.

В начало статьи

Совет 14. Используйте только явное описание типов данных

Еще одно изменение VB.NET, которое несет в себе хорошую и "не очень" новости.

Хороших новостей две. Первая — типы всех переменных должны быть описываться в явном виде. (В VB 6.0 по умолчанию — при отсутствии описания As... — устанавливался тип Variant.) Вторая — будет реализовано давно необходимое (и существующее в других языках) групповое описание типов данных, например:


Dim strFirstString, strSecondString As String

Отныне эта строка будет означать, что обе переменные — строковые, имеют тип String. Но как раз здесь кроется и серьезная проблема — ведь точно такая же строка в VB 6.0 означала, что strFirstString имею тип Variant. (О чем говорилось ранее — один и тот же код является синтаксически правильным, но имеет разных смысл в различных версиях VB). Соответственно, код


Dim strFirstString, strSecondString As String 
strFirstString = 1.2

в VB 6.0 является работоспособным, в VB.NET — нет.

В начало статьи

Совет 15. Забудьте о Def<type>

Это новшество непосредственно связано с описанным выше. В VB (в наследство от древних версий Basic) имелась группа операторов — DefBool, DefByte, DefInt и т.д., которая позволяла устанавливать тип переменной ил функции по первой букве идентификатора (если не указан тип в явном виде). Это было довольно удобно для группового описания типов, например:


DefInt I-N

означало, что оператор


Dim iMyValue, nYourValue

объявляется переменные типа Integer. Такой прием часто использовали Fortran-программисты при переходе в Basic (в очень старые времена в Фортране переменные, начинающиеся на I-N, автоматически считались целочисленными).

Но все же использование оператора Def<type> всегда имело один подводный камень, и поэтому его удаление из синтаксиса можно считать полезным. Ведь данное объявление размещается в начале модуля и и распространяется только на его переменные. Соответственно, при переносе программного фрагмента из модуля в модуль (например, процедуры) интерпретация кода зависела от установок конкретного модуля — наличие потенциальных ошибок в этой случае совершенно очевидно.

Но если, разработчик использовал одинаковый набор операторов Def<type> во всех своих программах, то это позволяло быстро ориентироваться в типах переменных, без изучения соответствующих объявлений. Однако, то же самое можно получит просто, приняв для себя строгую систему префиксов переменных.

Вместе с тем, следует подчеркнуть, что в VB.NET сохранена возможность использования суффиксов для определения типов данных (но только для тех типов, которые перешли в наследство от MS Basic/DOS):


 Суффикс   Тип переменной

 $         String
 %         Integer
 &         Long
 !         Single
 #         Double
 @         Currency (в VB.NET не поддерживается)

То есть описание


Dim FirstValue$, SecondValue%

эквивалентно


Dim FirstValue As String, SecondValue As Integer

В начало статьи

Совет 16. Замените вычисляемый Goto/Gosub на Select

Конструкция вычисляемого Goto/Gosub является типичным рудиментом Basic 60-х годов. О ней многие VB-программисты вообще не знают и правильно делают (само использование меток внутри процедуры — это плохой стиль программирования). Тем не менее, следует помнить, что конструкция типа


On xValue Goto 100, 200, 300, 400

легко меняется на


Select Case x
  Case 1
     ' тут выполняется код для метки 100
  Case 2
... End Select

В начало статьи

Совет 17. Замените GoSub/Return на Call Sub

Конечно же, это тоже рудимент старинного Basic, но то, что о нем многие забыли, в данном случае не очень хорошо. В результате довольно часто встречаются такие конструкции кода:


Select Case SomeValue
  Case 0
    MyString$ = SomeGirl$ & "+" & SomeBoy$
    MsgBox MyString$
  Case 1
    MyString$ = SomeGirl$ & "-" & SomeBoy$
    MsgBox MyString$
  ...
End Select

(Понятно, что это лишь пример. В реальности объем вычислений и число повторов могут быть гораздо значительнее.) Конечно, можно преобразовать программу с использование функции:


Select Case SomeValue
  Case 0: MyString$ = MyFunction$(SomeGirl$, "+", SomeBoy$)
  Case 1: MyString$ = MyFunction$(SomeGirl$, "-", SomeBoy$)
End Select

Однако тут возможно возражение из-за снижения быстродействия (передача параметров занимает много времени). Вот как раз тут и можно эффективно использовать конструкцию GoSub:


Select Case SomeValue
  Case 0: MyDel$= "+": GoSub MyFunction
  Case 1: MyDel$= "-": GoSub MyFunction
End Select

... MyFuction:
    MyString$ = SomeGirl$ & MyDel$ & SomeBoy$
    MsgBox MyString$
Return

Здесь видно, что GoSub/Return является очень удобной (к тому же эффективнее с точки зрения ресурсов — памяти и времени выполнения) конструкцией для реализации повторного используемого кода внутри процедуры с использованием ее внутренних переменных.

Теперь Gosub/Return исключается из VB.NET и я рекомендую заменить ее обращением к подпрограмме статуса Private, с использованием переменных уровня модуля. Это может выглядеть так:


' объявление переменных на уровне модуля: Dim  MyString$, SomeGirl$, SomeBoy$ 
'==============

Select Case SomeValue
  Case 0: Call MySub$("+")
  Case 1: Call MySub$("-")
End Select

Private Sub MySub (Mydel$)
    MyString$ = SomeGirl$ & MyDel$ & SomeBoy$
    MsgBox MyString$
End Sub

Но код тут будет почти таким же эффективным, как с применением GoSub/Return (минимум передаваемых параметров).

В начало статьи