Главная страница Visual 2000
· Общий список статей
Публикации в журнале BYTE/Россия
· Публикации на тему MS .NET
Андрей Колесов
© Андрей Колесов, 2001Совет 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 (минимум передаваемых параметров).