СТАТЬЯ
04.07.02

А ты готов к Visual Basic.NET?

© Андрей Колесов
Статья была опубликована на сайте www.bytemag.ru

Как давно известно всем Visual Basic-разработчикам, в конце нынешнего года ожидается новая версия Visual Basic, которая должна была иметь порядковый номер 7.0, но неожиданно получила имя собственное - .NET. Такая смена обозначения версий представляется весьма символичной -- судя по всему, грядет самое решительное обновление этой популярной системы программирования за все 10 лет ее существования (Visual Basic 1.0 появился в 1991 г.). Так что вполне вероятно, что очередная версия через пару лет будет уже называться Visual Basic.NET 2.0...

Как мы уже писали ранее*, в будущей версии Visual Basic.NET Visual Basic-программистов ожидает огромное число новшеств. Сюрпризов будет много и боюсь, что не все из них будут восприняты разработчиками с ликованием. Один из неприятных "подарков" заключается в том, что впервые за десятилетнюю историю Visual Basic нарушается совместимость программного кода "снизу вверх".


*Андрей Колесов, "В ожидании Visual Studio.NET", Byte/Россия №1/2001.

Microsoft обещает создать специальные средства для модификации кода приложений, созданных в предыдущих версиях, но даже если это случится, то почти наверняка далеко не все 100% ваших программ, написанных на Visual Basic 6.0, будут работать в Visual Basic.NET. Самое неприятное в этой ситуации - то, что некоторые старые конструкции будут правильными с точки зрения синтаксиса и транслятор не выдаст сообщения об ошибках, но в Visual Basic.NET этот код будет работать не так, как в Visual Basic 6.0.

Хотелось бы особо подчеркнуть, что речь идет в основном об изменениях в синтаксисе языка, а не в функциональности системы программирования. Рассмотрение новых функций и средств Visual Basic -- это тема отдельного разговора.

Важно отметить еще вот что. То, что известно сейчас, это результат знакомства с Visual Basic.NET Beta 1 и материалами Microsoft (т.е. это информация на начало 2001 года). Мне кажется, что корпорация в настоящее время внимательно изучает реакцию сообщества разработчиков на предлагаемые новшества и к моменту появления окончательной версии состав инноваций может измениться (правда, в обе стороны -- что-то исчезнет, а что-то добавится).

Надо сказать, что Visual Basic.NET уже вызвал у мирового сообщества Visual Basic-программистов множество реакций, и среди них немало негативных. На эту тему идут многочисленные дискуссии в Интернете. В частности, один из критиков нововведений, Карл Петерсон, создал Web-страницу под красноречивым названием "Visual Basic.NOT", где привел "неполный" (!) перечень расхождений (около 80 позиций) между Visual Basic 6.0 и Visual Basic.NET. Во всех этих обсуждениях довольно много эмоций ("Visual Basic.NET -- это уже не настоящий Basic", "нам не нужны ваши новшества" и т.п.), но за ними скрывается серьезный прагматичный аспект -- надежная миграция с одной версии на другую не будет обеспечена, код существующих приложений придется переписывать.

В свою очередь, Microsoft занимает пока твердую позицию, заявляя, что большинство Visual Basic-разработчиков одобряет изменения в Visual Basic.NET. И объясняет, что корпорация приняла трудное для себя решение о радикальной коррекции Visual Basic, понимая необходимость перехода от PC-ориентированной модели вычислений к Web-ориентированной.

Так или иначе, но сейчас мы наблюдаем самое сильное противостояние Basic-программистов с поставщиком инструментария за все время существования Visual Basic, причем раньше разработчики требовали нововведений, а сейчас протестуют против них. (Нечто похожее было в начале 90-х годов при переходе от MS Basic for DOS к Visual Basic for Windows. Тогда Microsoft более двух лет была вынуждена поддерживать оба направления, выпустив даже мертворожденный Visual Basic for DOS.) Чем закончится нынешнее противостояние, сказать трудно. Скорее всего, Microsoft будет решительно вести свою линию. Впрочем, стоит вспомнить историю пятилетней давности, когда, увидев негативную реакцию пользователей, корпорация решила продолжить выпуск Visual FoxPro (его очередная версия должна появиться и в нынешнем году).

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

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

1. Следует признать, что многие изменения синтаксиса в Visual Basic.NET очень полезны и их нужно было реализовать раньше (точнее, не допускать всяческих несуразностей изначально). Это касается совершенно неясного понятия Null, дубликатных функций типов String и Variant (например, Left$ и Left), дубликатных логических конструкций (Do и White), несоответствия свойств (элемент управления Label использует свойство Caption, которое по смыслу соответствует свойству Text всех остальных компонентов) и т.д.

2.Такое приведение синтаксиса языка в порядок, а также удаление явных рудиментов языка (Gosub/Return в случае Visual Basic) -- довольно обычное дело. Но вот как это делается, например, при модификации стандарта FORTRAN (раз в 7-10 лет): в очередном стандарте сразу публикуется список конструкций, которые, скорее всего, не попадут в следующую версию.

3.Модификация внутренних механизмов реализации тех или иных функций вполне понятна. Но мне кажется, что это можно было сделать в рамках традиционного синтаксиса Basic, не нарушая преемственности кода (речь тут идет о переносе ряда функций из внутренних библиотек во внешние объекты). Ведь по большому счету и раньше основная часть функций Visual Basic была реализована через Win API, а Visual Basic-операторы представляли собой просто удобный и безопасный (что очень важно) способ обращения к средствам Windows.

4. Изменение смысловой нагрузки одной и той же конструкции представляется непонятным и нарушающим простые принципы совместимости кода.

5. Самое "забавное" в нововведениях Visual Basic.NET -- Microsoft отказывается от вольностей в Visual Basic-программировании, которые сама же ввела и за которые всегда подвергалась критике со стороны профессионалов. Речь идет о широком использовании универсальных переменных типа Variant и неявного преобразования типов данных, установки свойств объектов по умолчанию и пр. Тем, кто не попался на удочку подобного "облегчения жизни" (а очевидных проблем, вытекающие из таких "послаблений", могли не видеть только новички от программирования), переходить на Visual Basic.NET будет гораздо проще.

Перенос проектов из Visual Basic 6.0 в Visual Basic.NET

Системы Visual Basic 6.0 и Visual Basic.NET могут быть установлены на одном компьютере и работать одновременно, точно так же, как и приложения, разработанные с помощью этих инструментов. Компоненты, написанные с помощью Visual Basic.NET, могут взаимодействовать с СОМ-компонентами, созданными в более ранних версиях Visual Basic. Например, можно подключить элемент управления ActiveX, реализованный в Visual Basic 6.0, к Windows-форме Visual Basic.NET; приложение Visual Basic.NET может использовать COM-объект Visual Basic 6.0. И, наоборот, -- к проекту Visual Basic 6.0 можно добавить ссылку на библиотеку Visual Basic.NET.

Visual Basic.NET не будет напрямую поддерживать совместимость с проектами Visual Basic 6.0. Но он содержит Upgrade Wizard (мастер обновления), который по шагам будет выполнять преобразование программы старого формата в новый проект Visual Basic.NET (начальный проект остается без изменений). Этот процесс односторонний -- проекты Visual Basic.NET нельзя открывать в Visual Basic 6.0.

В процессе обновления проектов выполняется модернизация синтаксических конструкций и замена Visual Basic 6.0 Forms на Windows Forms (последние имеют иную объектную модель, хотя и похожую во многом на Visual Basic 6.0 Forms).

Однако целый ряд возможностей и функций Visual Basic 6.0 в Visual Basic.NET в принципе не будет поддерживаться (например, некоторые виды проектов и элементов управления). Соответствующую модернизацию придется делать "руками".

В то же время Visual Basic.NET содержит ряд встроенных средств, реализацию которых ранее приходилось выполнять с помощью прикладного кода. Например, так это нужно делать для автоматической "привязки" положения кнопки к правому нижнему краю формы при изменении размеров последней. В Visual Basic.NET это решается с помощью установки нового свойства Anchor.

В процессе обновления проекта Visual Basic 6.0 мастер Visual Basic.NET сам находит подобные места потенциальной модификации, помечает их комментариями (с текстом, начинающимся словами TO DO) и формирует специальный "отчет обновления". Кроме того, каждый такой фрагмент кода отражается в новом окне Task List (список заданий), с помощью которого разработчик может быстро перемещаться по нужным компонентам проекта.

Конечно, было бы крайне желательно, чтобы протоколировались (комментарии, отчет) и все изменения, выполненные автоматически.

Качество существующего варианта Upgrade Wizard требует дополнительного изучения, и можно надеяться, что по мере доводки системы до окончательного релиза его функциональность будет повышаться (мы обсудим этот вопрос в последующих публикациях).

А теперь перейдем к советам.

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

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

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

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

Совет 3. Будьте внимательны при копировании фрагментов кода через буфер обмена

Такой прием часто применяется при работе с повторно используемыми фрагментами кода. Многие разработчики хранят подобные коллекции программ в различных хранилищах (начиная от текстовых файлов и заканчивая хранилищами Code Librarian), и перенос данных оттуда часто выполняется именно таким образом. Например, я порой использую подобный прием, когда нужно переписать нужную процедуру из старого проекта на Visual Basic 5 (и даже на Visual Basic 3) в новую программу. Понятно, что в этом случае нельзя ждать автоматического преобразования кода из Visual Basic 6.0 в Visual Basic.NET -- вся ответственность ложится на разработчика.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В Visual Basic.NET для метки нужно вместо Caption использовать свойство Text (оно применяется для хранения содержимого в подобных элементах управления). Если же вы хотите непременно сократить усилия по написанию кода, то можно предложить такой вариант:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

то Upgrade Wizard последнюю строку обновит:

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

Теперь можно будет обращаться к тем элементам управления, для которых в явном виде указан статус Public 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. Готовьтесь к изменению типов целочисленных переменных

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

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

Целые переменные Visual Basic 6.0 Visual Basic.NET
16-разрядные Integer Short
32-разрядные Long Integer
64-разрядные
-
Long

 

 

 

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

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

Dim x As Integer
Dim y As Long

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

Dim x As Short
Dim y As Integer

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Dim strFirstString, strSecondString As String

Отныне эта строка будет означать, что обе переменные -- строковые, имеют тип String.

Но как раз здесь кроется и серьезная проблема -- ведь точно такая же строка в Visual Basic 6.0 означала, что strFirstString имеет тип Variant. (О чем и говорилось выше -- один и тот же код синтаксически правилен, но имеет разный смысл в различных версиях Visual Basic). Соответственно, код

Dim strFirstString, strSecondString As String
strFirstString = 1.2

в Visual Basic 6.0 работает , а в Visual Basic.NET -- нет.

Совет 16. Забудьте о Def

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

DefInt I-N

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

Dim iMyValue, nYourValue

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

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

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

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

Суффикс Тип переменной
$ String
% Integer
& Long
! Single
# Double
@ Currency (в Visual Basic.NET не поддерживается)

 

 

 


Это значит, что описание

Dim FirstValue$, SecondValue%

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

Dim FirstValue As String, SecondValue As Integer

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

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

On xValue Goto 100, 200, 300, 400

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

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

 

 

 


Совет 18. Замените 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 исключается из Visual Basic.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 (минимум передаваемых параметров).

В мировом (в первую очередь американском) сообществе VB-программистов продолжаются весьма эмоциональные споры вокруг будущей версии Visual Basic. По оценкам экспертов журнала Visual Basic Programmer's Journal, большинство разработчиков одобряют технологию .NET, но их благодарность корпорации Microsoft никак нельзя назвать безграничной.

Тем не менее можно констатировать, что многомиллионная (по некоторым оценкам, от 2 до 4 млн. человек) армия пользователей VB-инструмента разделилась на две части. Сторонники новшеств технологии .NET (во главе с Microsoft) упирают на то, что с помощью нового Visual Basic они получат возможность создавать приложения масштаба предприятия, в том числе Web- и серверные приложения. Противники (точнее, критики) говорят о серьезной угрозе стабильности огромной базы существующего VB-кода. Собственно, почти все согласны с необходимостью реформирования Visual Basic, но высказывают настойчивые пожелания обеспечить более высокую совместимость с существующими версиями и растянуть реализацию всех новшеств на несколько последующих версий пакета.

При этом понятно, что накал дискуссий определяется не эмоциями, а чисто практическими интересами — все разработчики понимают, что реализация новшеств Visual Basic.NET может серьезно повлиять на их личную судьбу. Есть опасения, что переход от нынешней архитектуры Windows к будущей .NET может оказаться столь же болезненным, как переход в начале 90-х от DOS к Windows: значительная часть DOS-программистов просто не смогла (в том числе и чисто психологически) адаптироваться к новым методам разработки.

Сейчас никто не отрицает вероятность того, что Microsoft пойдет на некоторые уступки критикам, но все уверены, что корпорация будет продвигаться по выбранному ее руководством курсу, нацеленному, в частности, на завоевание сегмента крупных корпоративных клиентов. По крайней мере, вся десятилетняя история Visual Basic показывает, что за внешней внимательностью к запросам разработчиков лежит довольно жесткая линия стратегии Microsoft, которая ведет сообщество программистов в нужном корпорации направлении.

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

А теперь перейдем к советам...

Совет 19. Будьте внимательны при определении массивов

При работе с массивами VB-программистов ожидает целый ряд сюрпризов, причем не очень приятных. Общие рекомендации таковы: исключите использование оператора Option Base 1 (его нет в Visual Basic.NET), применяйте массивы с нулевой нижней границей индекса и пересмотрите варианты динамического определения массивов.

Приверженцы истинного Basic* могут радоваться — мы возвращаемся в далекое прошлое: теперь в "родном" варианте Visual Basic.NET поддерживает только массивы с нулевой нижней границей.


*Кстати, в середине 80-х годов Томас Курц, один из создателей первого Basic (это было в 1964 г.), разработал систему, которую назвал True Basic. Тем самым он хотел подчеркнуть, что многие другие Basic-инструменты отошли от начальных канонов этого языка.

Но как раз здесь программистов ожидает «подводный камень» — одна и та же конструкция в Visual Basic.NET и во всех предыдущих версиях будет работать по-разному. Иначе говоря, фрагмент кода.

Dim Arr(4)
For i = LBound(Arr) To 4
Arr(i) = 0
Next

 

 


работавший всегда безукоризненно, в Visual Basic.NET выдаст ошибку при i = 4. Дело в том, что определение массива:

Dim Arr(N)

во всех версиях Basic интерпретировалось как

Dim Arr (0|1 To N)

(0|1 — в зависимости от оператора Option Base), т.е. N обозначало верхнюю границу индекса. Но в Visual Basic.NET это будет указывать число элементов:

Dim Arr (0 To N-1)

Тут полезно напомнить, что в Visual Basic и ранее допускалось два формата описания размерности массива (на примере одномерного):

Dim Arr(N)

и

Dim Arr(lowIndex To hightIndex)

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

Dim Arr(0 To N)

Затем, чтобы обеспечить совместимость с FORTRAN (там нумерация начиналась с 1), был введен управляющий оператор Option Base 0|1, который позволял устанавливать нижнюю границу с нуля или единицы. Но это породило проблему неопределенности. Например, при копировании фрагмента кода Dim Arr(N) в некий модуль конкретное значение нижней границы массива определялось оператором Option Base именно этого модуля. В одном случае это мог быть 0, в другом — 1.

Таким образом, только явное задание нижней границы может устранить эту неопределенность и минимизировать проблемы при переходе в Visual Basic.NET. А еще лучше, если при обработке массива вы будете постоянно контролировать текущие значения границ индекса. Такой код гарантирует, что вы не выйдете за пределы индекса:

For i = LBound(Arr) To UBound(Arr)
Arr(i) = 0
Next

 

 


Но сложности при использовании ненулевой нижней границы останутся — все такие массивы будут преобразованы в массивы типа Wrapper Class, т.е. строка

Dim a(1 To 10) As Integer

поменяется на

Dim a As Object = New VB6.Array(GetType(Short), 1, 10)

Проблема заключается в том, что такие массивы работают заметно медленнее по сравнению с "родными" и существуют некоторые ограничения на их применение. Например, wrapper-массивы нельзя передавать в C-классы и в процедуры, использующие параметры типа Array.

Что касается динамического определения массива, то теперь конструкция

Dim v
ReDim v(10) ' работает в Visual Basic 6.0

работать не будет — переменная сразу должна быть определена как массив:

Dim v(2)
ReDim v(10) ' работает в Visual Basic.NET

Совет 20. Откажитесь от неявного преобразования типов данных

Этому совету стоит следовать независимо от того, собираетесь ли вы переходить на Visual Basic.NET. В обоснование этого тезиса можно привести много примеров; мы ограничимся двумя. Так, некоторые программисты для управления состоянием флажка вместо конструкции:

Dim newDelete As Boolean If newDelete Then chkDeleteMe.Value = 1
Else
chkDeleteMe.Value = 0
End If

 

 

 


используют более короткий код:

chkDeleteMe.Value = -1 * newDelete

Тут надо иметь в виду несколько явных минусов второго варианта.

  1. Он кажется более коротким, но с точки зрения создаваемого машинного кода менее эффективен, по крайней мере, по скорости выполнения.
  2. Результат работы этого кода неочевиден. Не уверен, что любой VB-программист с ходу ответит, каков будет результат при DeleteMe = True.
  3. В Visual Basic.NET он не будет работать (об этом ниже).

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

strR1$ = Str$(2.34)
strR2$ = 2.34
Print strR1$, strR2$ ' будет напечатано 2.34 2,34

 

 

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

Совет 21. Забудьте о целочисленных значениях булевых переменных

Программный код

Dim i As Integer
i = True
If i = -1 Then
MsgBox "Истина"
Else
MsgBox "Ложь"
End If

 

 

 

 

будет выдавать в Visual Basic 6.0 — "Истина", а в Visual Basic.NET — "Ложь". Причина в том, что целочисленное значение True поменялось с -1 на 1. Рекомендации очевидны: используйте только тип данных Boolean для логических переменных и при работе с ними применяйте только имена констант True и False. Иными словами, приведенный выше пример следует записать так:

Dim i As Boolean
i = True
If i = True Then
MsgBox "Истина"
Else
MsgBox "Ложь"
End If

 

 

 

 

С одной стороны, изменение числового значения для True выглядит достаточно логично, так как булева алгебра всегда строилась на логике 0/1 (Ложь/Истина). К тому же это устраняет важное расхождение с языком C. Но, с другой стороны, это связано с некоторыми внутренними проблемами Visual Basic.

Появление в свое время значения -1 для True объясняется тем, что фактически в качестве булевой переменной используется целый тип данных и все операции с ними на уровне машинных команд выполняются путем поразрядных операций. Соответственно код

Dim a As Integer a = 0 ' ложь a = Not a

приводил к результату -1.

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

Но проблемой Visual Basic была (и остается проблемой Visual Basic.NET) возможность неявного преобразования целых чисел в булевы значения и наоборот. В результате выполнения следующего кода:

Dim intVar As Integer Dim blnVar As Boolean ...
blnVar = intVar

 

 

 

при любом ненулевом значении intVar результатом всегда будет True. А это приводит к достаточно нелепой ситуации, когда в результате последовательности присвоений изменяется исходное значение:

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 5
c = a
b = c
Print a; b

 

 

 

 

В Visual Basic 6.0 будет напечатано "5 -1", в Visual Basic.NET — "5 1". Заметим еще, что результат выполнения следующего кода совершенно неочевиден:

Dim a As Integer Dim c As Boolean a = 5 c = 0 MsgBox c Or a

 

 

Кто из читателей сможет, глядя на этот код, уверенно предсказать результат операции?

Совет 22. Нужно готовиться к разделению логических операций

Описанные выше проблемы совместной обработки логических и целых переменных связаны еще и с тем, что, например, ключевое слово And выступает в зависимости от контекста в роли или логического, или побитового And. В Visual Basic.NET эта неопределенность устранена — And соответствует только логической операции с переменными типа Boolean, а для побитовых преобразований целых чисел будут использоваться новые операторы — BitAnd, BitOr, BitNot, BitXor. Как следствие, приведенный выше код (последний фрагмент в предыдущем разделе) в Visual Basic 6.0 будет выдавать 5, а в Visual Basic.NET — True (1).

Покажем то же самое на примере следующего кода:

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 1
b = 2
c = a And b
MsgBox "Результат = " & c

 

 

 

 

В Visual Basic 6.0 будет получен ответ False (выполнялось поразрядное логическое умножение двух целочисленных переменных с последующим преобразованием в логическое значение), а в Visual Basic.NET — True (целые числа сначала были преобразованы в логические, а потом с ними выполнили операцию And).

Для обеспечения совместимости кода Visual Basic.NET включает функции VB6.And, VB6.Or и VB6.Not, которые эквивалентны существующим сегодня And/Or/Not (почему-то для Xor такой функции нет). Соответственно средства обновления кода преобразуют приведенный выше фрагмент следующим образом:

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 1
b = 2
c = VB.And(a, b)
MsgBox "Результат = " & c

 

 

 



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

Dim a As Integer
Dim b As Integer
Dim c As Boolean
a = 1
b = 2
c = (a <> 0) And (b <> 0)
MsgBox "Результат = " & c

 

 

 

 

В этом случае никаких проблем с переносом кода не будет и средства автоматического обновления просто не понадобятся.

Совет 23. Уделяйте еще больше внимания логическим операциям

В Visual Basic.NET будет повышена "интеллектуальность" логических операций для увеличения их быстродействия. Это означает, что вычисление:

Dim a As Boolean
Dim b As Boolean
Dim c As Boolean
a = b And c

 

 


будет завершено досрочно (с результатом False), если окажется, что b = False. Это очень хорошо, но тут есть «подводный камень», который виден из такого примера:

Dim b As Boolean
b = Function1() And Function2()

Дело в том, что если значением функции Function1 окажется False, то обращения к Function2 просто не будет (а это может потребоваться). Средства миграции выполнят замену кода:

 

Dim b As Boolean
b = VB6.And (Function1(), Function2())

но надежнее сразу записать программу в таком виде:

Dim b As Boolean
Dim c As Boolean
Dim d As Boolean
c = Function1()
d = Function2()
b = c And d

 

 



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

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

Me.WindowState = vbNormal MsgBox "Error!", vbCritical txtTextbox.Visible = True

 

 

 

Приведенный вариант гораздо лучше такого кода, использующего числовые литералы или переменные:

x = 16
Me.WindowState = 0
MsgBox "Error!", x
txtTextbox.Visible = -1

 

 

 

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

x = vbCritical
...
MsgBox "Error!", x

 

 

Еще одно важное преимущество — минимизация возможных осложнений при обновлении программ и переносе кода, например, при смене версий. В случае с переходом к Visual Basic.NET подобные проблемы как раз могут возникнуть, так как в нем изменены значения (и даже в некоторых случаях имена), в частности для той же True.

Рекомендация использовать константы относится не только к встроенным функциям Visual Basic, но и к создаваемому вами коду. Например, если у вас есть такой код, который увеличивает несколько переменных на одинаковую величину:

a = a + 2
b = b + 2

то даже для двух переменных имеет смысл написать код следующим образом:

Const myStep = 2
a = a + myStep
b = b + myStep

 

 

Это повышает надежность и упрощает обновление кода. Ведь переменных может быть гораздо больше, а приведенные строки кода могут быть в реальности разбросаны по программе (можно легко не заметить, где нужно выполнять обновления).

Совет 25. Для работы с датами используйте только тип Date

Во всех существовавших до сих пор версиях Visual Basic для хранения даты фактически использовались переменные типа Double (отдельный тип Date появился только в версии 4.0). Дата записана в числовом формате IEEE, при этом целая часть соответствует номеру суток, начиная от 30 декабря 1899 года, а дробная — времени суток. Возможно, этот формат сохранен и в Visual Basic.NET, но вольность в преобразовании дат с обработкой их как обычных чисел будет прекращена. Подобные нелепые конструкции, вполне допустимые в Visual Basic 6.0:

Dim a As Date
Dim d As Double
a = 1101.27
MsgBox a ' выдается05.01.1903 6:28:48
d = Now * 1.4 + 0.347
a = d
MsgBox a ' выдается 29.09.2041 4:48:35

 

 

 

 

в Visual Basic.NET работать не будут. Для обработки дат нужно использовать только набор соответствующих функций, которых более чем достаточно.

Совет 26. Не используйте недокументированные функции

Многие VB-программисты даже не подозревают о существовании недокументированных функций VarPrt, VarPrtArray, VarPrtStringArray, ObjPrt и StrPrt, позволяющих получать значения адреса памяти, где хранятся соответствующие переменные. Но они порой очень полезны при работе с Win API, в частности когда нужно выполнять изощренные операции с буферами.

Microsoft заявляет, что в Visual Basic.NET таких функций не будет. Впрочем, корпорация умалчивала об их существовании на протяжении десяти лет. Может быть, подобные функции останутся, но только под другими, секретными именами?

Совет 27. Не используйте LSet для структур

В Visual Basic 6.0 оператор LSet можно было использовать для присвоения переменной одного пользовательского типа значения переменной другого пользовательского типа. Теперь такая возможность исключена.

Совет 28. Лучше не использовать строки фиксированной длины

В Visual Basic.NET строки фиксированной длины не будут "родными" (не будут входить в состав базового набора типов данных, непосредственно поддерживаемых транслятором). Для обеспечения совместимости будет использоваться специальный объект, поэтому код Visual Basic 6.0:

Dim MyFixedLengthString As String * 12

будет преобразован в

Dim MyFixedLengthString As New VB6.FixedLengthString(12)

Но следует иметь в виду, что применение такого объекта будет ограничено. Например, его нельзя будет использовать при работе с функциями Win API. Таким образом, например, вместо варианта резервирования буфера:

Dim Buffer As String * 25

нужно писать:

Dim Buffer As String
Buffer = String$(25, " ")

Совет 29. Будьте внимательны при использовании строк и массивов в структурах

Еще одна ожидаемая проблема заключается в том, что при определении структур (которые также называются пользовательскими типами данных) не будет автоматически выполняться создание класса строки фиксированной длины и массива фиксированного размера. При обновлении такой структуры в Visual Basic.NET она будет помечаться комментарием с соответствующим предупреждением. Чтобы избежать проблем, лучше сразу заменить следующий код:

Private Type UserType UserArray(10) As Integer
UserFixedString As String * 30
End Type
Sub UserProc()
Dim UserVariable As UserType End Sub

 

 

 

 

на такой:

Private Type UserType UserArray() As Integer UserFixedString As String
End Type
Sub UserProc()
Dim UserVariable As UserType
ReDim UserVariable.UserArray(10) As Integer
UserVariable.UserFixedString = String$(30, " ")
End Sub

 

 

 

 

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

Совет 30. Не используйте As Any при обращении к Win API

Множество функций Windows API имеют возможность принимать параметры различных типов — интерпретация передаваемых данных выполняется в зависимости от значения других параметров. Пример такой функции — SendMessage, в которой в качестве последнего параметра может выступать как целое число, так и строка байтов произвольной длины. Для таких случаев Visual Basic использует описание параметров As Any, которое говорит о том, что в стек будет помещен некоторый адрес буфера памяти. Фактически это означает, что компилятор снимает с себя ответственность за контроль передаваемых данных.

Практически во всех рекомендациях по работе с Win API говорится о том, что необходимо особое внимание при использовании описания As Any, и дается совет использовать несколько псевдонимов (Alias) с созданием двух и более объявлений для одной и той же функции, причем в каждом из описаний указываются параметры определенного типа. В Visual Basic.NET это будет уже не пожелание, но требование — в нем исключена возможность использования типа As Any.

Мы рассмотрим возможности применения As Any, подстерегающие здесь программиста опасности и варианты использования Alias на примере функции lread:

Declare Function lread
Lib _ "kernel32" Alias "_lread" _
(ByVal hFile As Long, lpBuffer As Any, _
ByVal wBytes As Long) As Long

 

 

 

В Visual Basic аналог этого — оператор Get при чтении файлов типа Binary. Обратим сразу внимание на необходимость использования ключевого слова Alias в объявлении функции. Настоящие названия функции в библиотеке начинаются с символа «подчеркивание» (стиль, типичный для языка C), что не разрешается в Visual Basic.

В данном случае параметр lpBuffer — это именно адрес буфера, куда будут считываться данные (wBytes указывает число читаемых байтов). В качестве буфера может выступать простая переменная, массив, строка.

' чтение вещественного числа, 4 байта
Dim MyVar As Single
wBytes = lread (hFile&, MyVar, Len(MyVar)
...
' чтение 10 элементов массива
Dim MyArray(0 To 9) As Byte
wBytes = lread (hFile&, MyArray(0), Len(MyArray(0))* 10)

 

 

 

 

Обратите внимание: второй аргумент функции передается по ссылке, остальные — по значению.

Однако, если вы хотите прочитать символьные данные в строку переменной длины, вам нужно использовать обращение иного вида:

' чтение символьной строки, 10 символов
Dim MyVar As String MyVar = Space$(10)
wBytes = lread (hFile&, ByVal MyVar, Len(MyVar))

 

 

Здесь видно важное отличие от приведенного ранее примера — строковая переменная обязательно сопровождается ключевым словом ByVal. Если мы этого не сделаем, то будет передаваться не адрес строки, а адрес ее дескриптора, и фатальная ошибка будет неизбежна.

Чтобы обезопасить себя, можно добавить специальное описание этой же функции для работы только со строковыми переменными:

Declare Function lreadString _
Lib "kernel32" Alias "_lread" _
(ByVal hFile As Long, ByVal lpBuffer As String,_
ByVal wBytes As Long) As Long

 

 

 

При работе с этим описанием указывать ByVal при обращении уже не нужно:

wBytes = lreadString (hFile&, MyVarString, Len(MyVarString))

Правда, полный отказ от использования As Any имеет и свои минусы, в частности, как раз при работе с функцией lread — придется дублировать ее описания для всех возможных вариантов простых переменных.

Совет 31. Точно объявляйте способ передачи параметров

Обычно мы указываем способ передачи параметров — ByRef (по ссылке) или byVal (по значению) — только при работе с Win API (точнее, со всеми DLL-функциями). В предыдущем совете мы показали, как это важно. При работе с процедурами внутри среды Visual Basic исторически было принято, что по умолчанию параметры всегда передаются по ссылке. Но в Visual Basic.NET это изменилось — теперь по умолчанию все параметры будут передаваться по значению.

Безусловно, это положительное изменение, так как оно обеспечивает более надежное программирование — специальным образом должна описываться именно возможность возврата измененного параметра. Тем более, что двусторонний обмен данными встречается на практике гораздо реже, чем односторонний. Но при переходе от Visual Basic 6.0 к Visual Basic.NET это изменение может вызвать неприятности:

 

Dim a%, b%, c%
a = 0: b = 1: c = 2
Call MyTest(a, b, c)
MsgBox a & " " & b & " " & c
Public Sub MyTest(ByVal d%, f%, ByRef g%)
d = 10: f = 11: g = 12
End Sub

 

 

 


При работе в Visual Basic 6.0 будет получен результат

0 11 12

а в Visual Basic.NET:

0 0 12

Надеюсь, что средства миграции обеспечат замену описания подпрограммы на

Public Sub MyTest(ByVal d%, ByVal f%, ByRef g%)

но лучше определять в явном виде возвращаемые параметры уже сейчас.

Напомним, переход программ, написанных на Visual Basic 6.0, в среду Visual Basic.NET будет непростым: так, многие конструкции Visual Basic 6.0 не будут работать в новой версии системы. Более того, некоторые из них будут выполняться, но иначе, чем в текущей версии.

Дискуссия на эту тему завершается по той простой причине, что время споров истекло - финальная версия Visual Basic.NET появится до конца года, и если вы решили работать с ней (а куда деваться?), то нужно уже сейчас начинать писать приложения в этой среде. Кроме того, в июне вышла версия Visual Studio.NET Beta 2 (см. врезку "Что нового в Visual Studio.NET Beta 2"), и стало понятно, что ждать от Microsoft радикальных уступок в ответ на критику по поводу несовместимости Visual Basic 6.0 и Visual Basic.NET и проблем с переносом приложений не приходится.

Так или иначе, но в западной прессе дискуссионные публикации по поводу Visual Basic.NET сменились статьями на традиционную тему: как работать с новой версией системы (что и мы собираемся сделать в последующих номерах "BYTE/Россия").

Вместе с тем хотелось бы обратить внимание на статью Рассела Джонса "VB.NET против классического VB" (VB.NET Faces Off Against Classic VB), в которой он приводит 10 примеров, демонстрирующих преимущества новой версии. Хотел бы высказать свое несогласие с пафосом этой статьи - представляется совершенно очевидным, что каждая новая версия инструмента должна быть лучше предыдущей. Безусловно, в Visual Basic.NET реализованы многие очень интересные и полезные функции. Но суть-то проблемы заключается в том, что большинство новшеств можно было реализовать, обеспечивая совместимость версий. И примеры, приводимые американским автором, на самом деле как раз это демонстрируют.

В частности, одним из достоинств Visual Basic.NET Рассел Джонс называет то, что теперь порядок обхода элементов управления на форме (он задается свойством TabIndex) можно будет задавать с помощью встроенной команды Tab Order. Но ведь такая команда появилась уже давно - еще в составе Office 97/Visual Basic for Applications. Что мешало включить ее и в Visual Basic?

Конечно, очень здорово, что наконец-то будет реализована возможность динамического подключения элементов управления к форме в процессе выполнения приложения. Но ведь и в момент создания Visual Basic 1.0 в среде Windows 3.0 не было никаких технических проблем, которые могли бы помешать реализовать такую полезную функцию.

Безусловно, появление Visual Basic.NET - очень важный момент в истории этого популярного средства программирования. (Более того, весь пакет Visual Studio.NET знаменует собой качественно новый этап развития средств разработки на более высоком уровне интеграции.) В этой связи полезно напомнить, что в мае нынешнего года Visual Basic отметил десятилетний юбилей - его первая версия появилась в 1991 г. и впервые была продемонстрирована в СССР на выставке Softool'91 (см. в этом номере статью "Basic - этапы большого пути").

Изменения синтаксиса в Visual Basic.NET Beta 2

Прежде чем предложить читателю завершающую часть "Советов", нужно рассказать о некоторых изменениях синтаксиса Visual Basic.NET по сравнению с первой бета-версией.

Отметим, что с самого начала дискуссий о Visual Basic.NET никто не отрицал вероятность того, что Microsoft может пойти на некоторые уступки критикам. Однако, зная стиль работы корпорации, можно было уверенно утверждать, что уступки будут минимальными и, возможно, временными. По крайней мере, вся десятилетняя история Visual Basic наглядно демонстрирует, что за внешней внимательностью к запросам разработчиков скрывается довольно жесткая стратегическая линия Microsoft, которая ведет сообщество программистов в нужном корпорации направлении.

Выход бета-версии 2 показывает, что сколько-нибудь значительного числа "откатов" со стороны Microsoft ждать не приходится. Вот список некоторых новшеств (часть из них нужно учесть при изучении ранее опубликованных нами "Советов").

1. Описание массивов, например Dim a(10), будет работать так же, как и предыдущие 40 лет существования языка Basic. Иными словами, в данном примере 10 - это верхняя граница индекса массива, а не число его элементов, как это грозились сделать в Visual Basic.NET (об этом говорилось в совете 18-м). .

2. Операции And, Or, Not и XOR, как и ранее, будут использоваться и для логических, и для поразрядных операций. В первой бета-версии Visual Basic.NET эти операции выполнялись только с логическими переменными, а для целочисленных вводились дополнительные функции вида BitXXX (BitAnd и т.д.), которые теперь исключены (см. совет 21-й).

3. В совете 22-м мы говорили о повышении "интеллектуальности" логических операций. В частности, в выражении

a = A1 And A2

операнд A2 не будет анализироваться, если A1 = False. (Операнд A2 может представлять собой функцию, которую в любом случае желательно вычислить.) Теперь же подобный режим оптимизации нужно задавать в явном виде, используя специальные операторы AndAlso и OrElse, например так:

If x > 0 AndAlso x < 10 Then ...
(второе условие не будет проверяться, если x <= 0)
If x > 0 OrElse x <-10 Then
(второе условие не будет проверяться, если x > 0)

 

 

 

Мне кажется, что такое разделение логических функций искусственно и не так уж и нужно, поскольку коллизия с выражениями легко разрешается последовательным их вычислением

A1 = Function1() A2 = Function2() a = A1 And A2

4. Значение логической переменной True по-прежнему будет иметь целочисленное значение -1, а не 1, как планировалось (совет 20-й). Мне кажется, это не очень принципиально, поскольку общая рекомендация состоит в том, чтобы вообще не использовать неявное преобразование типов данных (в данном случае целочисленных и булевых). В этой связи отметим, что все же было бы полезно разделить логические операции с булевыми и беззнаковыми целыми числами.

5. Для сравнения двух объектных переменных (при проверке ссылок на один и тот же объект) по-прежнему будет использоваться ключевое слово Is (Visual Basic 6), а не простой знак равенства = (Visual Basic.NET Beta 1).

6. Теперь все классы наследуют метод ToString объекта System (родитель всех объектов в .NET), который преобразует числовое значение в текстовый вид. Однако тут следует иметь в виду, что разделитель целой и дробной части числа (точка или запятая) будет зависеть от национальных установок Windows.

Такой метод позволит порой существенно упростить код программы. Например, вот как выглядит функция получения уникального глобального кода в Visual Basic 6:

.

Private Declare Function CoCreateGuid Lib _
"ole32.dll" (buffer As Byte) As Long
Private Declare Function StringFromGUID2 Lib _
"ole32.dll" (buffer As Byte, ByVal lpsz As Long, _
ByVal cbMax As Long) As Long

Private Function getGUID () As String
Dim buffer(0 To 15) As Byte
Dim s As String
Dim ret As Long
s = String$(128, 0)
' получает численный код
ret = CoCreateGuid (buffer(0))
' преобразуем его в текст,
' используя недокументированную функцию StrPt
r ret = StringFromGUID2 (buffer(0), StrPtr(s), 128)
getGUID = Left$(s, ret - 1) ' отсекаем "хвост"
End Function

 

 

 

 

 

 

 

 


В Visual Basic.NET все это будет выглядеть гораздо компактнее:

Private Function getGUID () As String
getGUID = "{" & System.Guid.NewGUID.ToString & "}"
End Function

 

 

7. Для совместимости с функциями Visual Basic 6.0 используется пространство имен Microsoft.VisualBasic.Compatibility.VB6. Чтобы не приходилось писать такие длинные названия, при работе со старыми функциями теперь можно применять специальный оператор Import.

8. Ранее для обозначения коллекций объектов Visual Basic использовалось множественное число имени объекта (Parameters, Properties и т.д.) Теперь коллекции будут называться длиннее, но более понятно: ParameterCollection, PropertyCollertion.

9. В бета-версии 1 библиотека ADO.NET имела два важных пространства имен: System.Data.ADO для общих провайдеров данных и System.Data.Sql для провайдера SQL Server. Теперь эти имена заменены соответственно на System.Data.OleDb и System.Data.SqlClient.

Это далеко не полный перечень всех изменений в синтаксисе Visual Basic.NET. И можно предположить, что он не окончательный - в финальной версии нас могут ждать новые сюрпризы.

Еще несколько советов по переходу в Visual Basic.NET

Совет 32. Внимание при объявлении переменных. Visual Basic 6 поддерживает такую забавную конструкцию с объявлением переменной внутри исполняемого кода:

Do
Dim nTotal As Long
nTotal = nTotal + 1
Loop Until nTotal > 100 MsgBox "Результат = " & nTotal

 

 


В результате его выполнения выдается сообщение "Результат = 101". А в Visual Basic.NET вы получите системное сообщение об ошибке - "переменная nTotal не объявлена". Причина этого в том, что в Visual Basic.NET подобная переменная работает только внутри операторных скобок, в которых она определена (в данном случае Do Loop). Так что конструкция, выглядевшая в Visual Basic 6 довольно несуразной, получает весьма четкую смысловую окраску.

Кстати, для увеличения переменной на некий шаг теперь можно применять такой синтаксис

nTotal += 1

 

Совет 33. Откажитесь от использования Null. Честно говоря, я никогда не понимал глубокого смысла парадигмы Null, которая использовалась для обозначения особого, "нулевого" значения переменной типа Variant. Вполне естественно, что с исчезновением Variant из Visual Basic.NET удален и Null.

Совет 34. Готовьтесь к однозначности строковых функций. Как известно, в Visual Basic было два варианта функций обработки строки - с суффиксом $ и без него. Например, Left$ возвращала переменную типа строка, а Left - типа Variant. Теперь останется только Left - но возвращаться будет строка.

Совет 35. Используйте Visual Basic.NET Update Tool. По мнению Microsoft, этот инструмент, включенный в состав Visual Basic.NET, обеспечит автоматический перенос 95% приложений, написанных с помощью Visual Basic 6.0, в среду Visual Basic.NET. Он сможет выполнить следующие преобразования синтаксиса языка:

Что нового в Visual Studio.NET Beta 2

Помимо некоторых изменений в составе отдельных средств, Microsoft включила в бета-версию 2 еще несколько дополнительных возможностей для разработчиков.

Во-первых, на стартовой странице Visual Basic.NET появилась новая вкладка Web Hosting, с помощью которой можно получить список провайдеров ASP .NET Web, предоставляющих бесплатное Web-пространство для распространения законченных компонентов и приложений. Во-вторых, на вкладке стартовой страницы "Что нового?" имеется ссылка на огромный список утилит и компонентов независимых разработчиков в дополнение к Visual Studio.NET.

Следует также обратить внимание на то, что пока Visual Basic, Visual С++ и C# существуют только в объединенном варианте. Microsoft объясняет это тем, что у обоих средств очень много общих компонентов. Корпорация ничего не говорит о том, как будет выглядеть окончательный вариант поставки, но представляется весьма вероятным, что отдельных программ Visual Basic и Visual С++ больше не будет.

Не очень понятна и ситуация с поддержкой работы Visual Studio.NET в среде Windows 9x и Windows ME. В сопроводительной документации к бета-версии 2 подчеркивается, что она тестировалась в среде Windows NT 4.0, Windows 2000 и Windows XP. Что же касается Windows 98 и ME, то здесь лишь обещано, что в них будет поддерживаться "выполнение кода" (code execution). При этом непонятно, о чем идет речь - о работе среды Visual Studio.NET или о поддержке только создаваемых в ней приложений.

В мае Microsoft выпустила бета-версию нового набора для разработчиков мобильных Web-приложений на базе технологии ASP.NET - Microsoft .NET Mobile Web SDK Beta 1. Конструктор Mobile Web Forms Designer для создания мобильных Web-форм также включен в состав Visual Studio.NET Beta 2.

Изменения ожидают и разработчиков приложений масштаба предприятия: Visual Studio.NET Enterprise Edition будет поставляться в двух вариантах - Developer и Architect (для разработчиков и архитекторов систем соответственно). Пока не вполне ясно, каково соотношение этих двух версий (получается, что для полного цикла разработки нужно будет покупать два недешевых продукта), и о версии Architect говорится лишь то, что она будет нацелена на решение трех задач - моделирование приложений, моделирование баз данных и управление средой разработки.

В варианте Enterprise будет также использован механизм Open Tools Platform, который предоставляет весь набор инструментов, позволяющих интегрировать в среду программирования Visual Studio.NET решения сторонних разработчиков. Для привлечения третьих фирм - поставщиков инструментальных средств Microsoft объявила программу Visual Studio.NET Integration Program (VSIP). Одним из первых ее участников стала компания Rational Software, уже объявившая о поддержке данной платформы и интеграции своего средства Rational Suite с Microsoft Visual Studio.NET.

Дополнительная информация

 

Дополнительную информацию Вы можете получить в компании Interface Ltd.

Обсудить на форуме Microsoft
Отправить ссылку на страницу по e-mail


Interface Ltd.
Тel/Fax: +7(095) 105-0049 (многоканальный)
Отправить E-Mail
http://www.interface.ru
Ваши замечания и предложения отправляйте автору
По техническим вопросам обращайтесь к вебмастеру
Документ опубликован: 04.07.02