Глава 3. Выражения, операторы и передача управления

Глава №3.

Выражения, операторы и передача управления

В этой главе представлен базовый «арсенал» VB .NET. Большая часть материала сводится к краткому обзору концепций, присущих всем языкам программирования (например, переменных и команд цикла), и описанию базовых типов данных, в основном различных чисел и строк. Читатели, хорошо знакомые с VB6, могут бегло пролистать эту главу.

Лишь в нескольких примерах этой главы встречается реальный код, который может использоваться в серьезных программах VB .NET. Дело в том, что ни одна серьезная программа VB .NET не обходится без объектов, построенных по шаблонам, называемых классами, а эта тема будет рассматриваться в главе 4. Мы начнем с базовых конструкций языка, потому что в противном случае нам пришлось бы ограничиться примитивными классами, не обладающими никакой практической ценностью. В этой главе не рассматриваются классы, определяемые пользователем, и продемонстрированы лишь простейшие примеры использования встроенных классов .NET Framework, обладающих исключительно широкими возможностями.

Что же из этого следует? Как ни странно — то, что написанные в этой главе программы весьма близки по стилю к традиционному программированию ранней эпохи BASIC и даже предшествовавшей ей эпохи Fortran и COBOL (если не считать некоторых странных, но необходимых синтаксических конструкций). В частности, в отличие от программ из дальнейших глав, у них всегда есть четко определенные начало и конец, и управление передается от начала к концу (хотя управление может передаваться специальными командами).

Как говорилось во введении, мы постараемся приводить программы, написанные в нормальном стиле .NET, по возможности избегая искусственной совместимости с VB6.

Консольные приложения

Каждое приложение VB .NET должно иметь точку вто§а. В точке входа содержится код, автоматически выполняемый при запуске, после чего управление передается остальному коду программы. В относительно простых графических приложениях точка входа может ассоциироваться с начальной формой, как в VB6. Но как было показано в главе 1, код форм Windows достаточно сложен и поиск точки входа может вызвать определенные затруднения. В этой главе рассматриваются только консольные приложения, работающие в консольном окне (наподобие окна сеанса DOS). Да, VB .NET позволяет легко создавать традиционные консольные приложения, часто применяемые при программировании серверных сценариев:

Точкой входа консольного приложения является процедура Sub Mai n модуля (аналог процедуры Sub Mai n в VB6). Если выбрать в диалоговом окне New Project значок консольного приложения (Console Application), VB .NET автоматически генерирует «скелет» приложения с точкой входа — процедурой Sub Main:

Module Module1

Sub Main()

End Sub

End Module

В отличие от VB6, в первой строке задается имя модуля (команда выделена жирным шрифтом). В данном примере используется имя Modul el, принятое по умолчанию. По правилам имя модуля должно совпадать с именем файла. Допустим, вы изменили имя модуля в первой строке: Module Testl При попытке запустить консольное приложения выводится сообщение об ошибке:

Startup code 'Sub Main' was specified in 'Test.Modulel'.

but 'Test.Modulel' was not found

Переименование модуля после его создания выполняется следующим образом:

  1. Измените имя модуля в окне программы.
  2. Измените имя файла модуля в окне решения.
  3. Щелкните правой кнопкой мыши в строке ConsoleApplication окна решения и выберите в контекстном меню команду Properties.
  4. Убедитесь в том, что в списке Startup object появившегося диалогового окна (рис. 3.1) выбрано имя модуля.

По аналогии с VB6 программа VB .NET (решение) может состоять из нескольких модулей, но наличие процедуры Sub Main допускается только в одном модуле. Приложение завершается по достижении команды End Sub процедуры Sub Mai n. Например, легендарная программа «Hello world» выглядит следующим образом:

Module Modul el

Sub Main()

Console.WriteLine("Hello world")

End Sub End Module

Если запустить эту программу в IDE, на экране очень быстро мелькнет (и тут же исчезнет) окно DOS со словами «Hello world». Окно закрывается по завершении обработки команды End Sub.

Рис. 3.1. Диалоговое окно свойств консольного приложения

Если включить в программу строку, выделенную ниже жирным шрифтом, консольное окно остается на экране до нажатия клавиши Enter (чрезвычайно полезный метод ReadLine() описан ниже).

Module Modulel

Sub Main()

Console.WriteLine("Hello world")

Console. ReadLine()

End Sub

End Module

Несмотря на простоту, эти две программы демонстрируют одну из ключевых особенностей программирования VB .NET (и вообще программирования на любом объектно-ориентированном языке): вы обращаетесь к объектам с запросом на выполнение операций. По аналогии с VB6 точка («.») используется для обращения к членам объектов и классов. Хотя обычно при вызове указывается объект (конкретный экземпляр, созданный на базе класса), в некоторых случаях вместо него указывается имя класса. В качестве примера возьмем следующую строку:

Console.WriteLine("Hellо world")

В ней вызывается метод Wri teLi ne класса Console, предназначенный для вывода текста с последующим переводом строки (в объектно-ориентированном программировании, как и в VB6, функции классов обычно называются методами). Метод WriteLine принадлежит к числу общих (shared) методов, также называемых методами класса. Общие методы подробно описаны в главе4. При вызове WriteLine выводимый текст заключаете в кавычки и помещается в круглые скобки. Во вторую версию программы «Hello world» добавлен вызов метода ReadLi ne, ожидающего нажатия клавиши Enter (метод ReadLi ne обычно используется в правой части команды присваивания, чтобы введенный с консоли текст был сохранен в заданной переменной — см. следующее примечание).

В приведенных программах следует обратить внимание на пару неочевидных обстоятельств. Как было сказано выше, при вызове метода обычно указывается конкретный экземпляр класса. Исключение из этого правила составляют особые методы класса, называемые общими методами. Общие методы существуют на уровне класса, а не его отдельных экземпляров. Другая тонкость заключается в том, что Console входит в пространство имен System, поэтому полный вызов метода выглядит так: System.Console.Writeline("Hello world"). В данном примере это не нужно; причины изложены в главе 4 при более подробном описании пространств имен.

Пользователям предыдущих версий VB следует учесть, что круглые скобки при вызове методов обязательны — обычно IDE добавляет их автоматически, но лучше не забывать об этом. Ключевое слово Call разрешено, но теперь в нем нет необходимости.

Команды VB .NET

При вводе программ VB .NET во внешнем редакторе вы не сможете воспользоваться средствами IntelliSense. Мы рекомендуем использовать IDE, поскольку технология IntelliSense значительно упрощает программирование в такой сложной среде, как .NET (конечно, для этого вам придется перейти от бесплатно распространяемого .NET SDK к Visual Studio). Редактор IDE даже исправляет некоторые распространенные ошибки — например, пропуск круглых скобок при вызове некоторых методов.

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

Тем не менее VS .NET IDE пытается оформлять программы VB .NET по своим правилам. Первые символы ключевых слов преобразуются к верхнему регистру, а строки дополняются пробелами для удобства чтения (End SUB преобразуется в End Sub и т. д.). Регистр символов в именах методов VB .NET определяется по схеме Pascal (слова начинаются с прописных букв, остальные буквы строчные). Альтернативная схема выбора регистра (writeLine) для методов VB .NET обычно не используется.

Номера строк в командах VB .NET практически не используются, хотя строки программы могут нумероваться, причем каждая команда обычно расположена в отдельной строке. Чтобы продолжить команду в следующей строке, завершите ее символом подчеркивания (_), отделенным одним или несколькими пробелами. Таким образом, если строка не завершается символом подчеркивания, нажатие клавиши Enter является признаком конца команды (в Visual Basic команды не разманд можно разместить в одной строке, разделив их символом «:», но обычно так не поступают. Если введенная строка не помещается в окне, IDE прокручивает строку вправо по мере необходимости.

Комментарии

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

Sub Main()

Console.WriteLine("Hello world")

' Игнорировать значение, возвращаемое методом ReadLine

Console. ReadLine()

End Sub

Во втором варианте используется старое ключевое слово Rem, которое появилось в BASIC в начале 1960-х годов!

При включении комментариев в конец строки проще воспользоваться апострофом, поскольку ключевое слово Rem придется отделять двоеточием. В VB .NET не предусмотрено языковых средств для комментирования нескольких строк, хотя на панели инструментов присутствует кнопка, упрощающая создание таких комментариев.

В отличие от языка С#, обладающего встроенными средствами построения комментариев XML, в VB .NET документация XML будет создаваться отдельной надстройкой (add-in).

Переменные и присваивание

Имена переменных в VB .NET имеют длину до 255 символов и обычно начинаются с буквы в кодировке Unicode (за дополнительной информацией о Unicode обращайтесь на сайт www.unicode.org), хотя также допускается символ подчеркивания. Далее следует произвольная комбинация букв, цифр и символов подчеркивания. Все символы имени являются значимыми, но регистр символов игнорируется (как вообще в VB .NET); считается, что firstBase и firstbase — одна и та же переменная. Присваивание выполняется при помощи знака =, как и в более ранних версиях VB:

theYear = 2001

В .NET Framework используются новые правила присваивания имен переменным, заметно изменившиеся по сравнению с VB6. В соответствии рекомендациями, приведенными в MSDN, применять венгерскую запись нежелательно, а значимые имена переменных (то есть не состоящие из одной буквы, как i или t) должны оформляться в альтернативной схеме выбора регистра. В прежних версиях VB обычно использовалась схема Pascal.

Имена переменных не могут совпадать с последовательностями, зарезервированными VB .NET (список для текущей версии приведен в табл. 3.1), однако это ограничение можно обойти, заключив имя переменной в квадратные скобки. Например, переменная не может называться Loop, а имя [Loop] подойдет — хотя делать это не рекомендуется. Зарезервированные слова внутри имен переменных допустимы (скажем, loopit — вполне нормальное имя). При попытке использования ключевого слова в качестве имени переменной VB .NET подчеркивает его и информирует об ошибке (при помощи экранной подсказки).

Таблица 3.1. Ключевые слова текущей версии VB .NET

AddHandler

AddressOf

Alias

And

Ansi

As

Assembly

Auto

Binary

BitAnd

BitNot

BitOr

BitXor

Boolean

ByRef

Byte

ByVal

Call

Case

Catch

CBool

CByte

CChar

CDate

CDec

CDbl

Char

CInt

Class

CLng

CObj

Compare

Const

CShort

CSng

CStr

Ctype

Date

Decimal

Declare

Default

Delegate

Dim

Do

Double

Each

Else

Elself

End

Enum

Erase

Error

Event

Exit

Explicit

ExternalSource

False

Finally

For

Friend

Function

Get

GetType

GoTo

Handles

If

Implements

Imports

In

Inherits

Integer

Interface

Is

Lib

Like

Long

Loop

Me

Mod

Module

Mustlnherit

MustOverride

MyBase

MyClass

Namespace

Next

New

Not

Nothing

Notlnheritable

NotOverridable

Object

Off

On

Option

Optional

Or

Overloads

Overridable

Overides

Pa ram Array

Preserve

Private

Property

Protected

Public

RaiseEvent

Readonly

Re Dim

REM

RemoveHandler

Resume

Return

Select

Set

Shadows

Shared

Short

Single

Static

Step

Stop

Strict

String

Structure

Sub

SyncLock

Text

Then

Throw

To

True

Try

TypeOf

Unicode

Until

When

While

With

With Events

WriteOnly

Xor




 

Литералы и их соответствие типам данных

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

Хотя возможность непосредственной интерпретации данных предусмотрена в любом языке программирования, решить, как именно следует интерпретировать те или иные данные, иногда бывает непросто. Наверное, все согласятся с тем, что 3 — это число 3 и его следует интерпретировать именно так. Но что такое число 3 с точки зрения компилятора? Сколько байт памяти следует под него выделить? Теоретически для хранения числа 3 хватит 2 бит, но в современных языках программирования обычно происходит не так.

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

  • Байт: фактически вы сообщаете компилятору, что для хранения числа следует выделить минимальный объем памяти.
  • Короткое целое: старый тип Integer из VB6.
  • Целое .NET: старый тип Long из VB6 (компилятор выделяет для хранения числа 4 байта).

К счастью, символ 3 никогда не будет автоматически интерпретироваться как строковая константа (если не переопределять стандартную логику VB). В VB .NET строки и числа по умолчанию не смешиваются — более подробно эта тема рассматривается в разделе «Преобразования разнотипных значений» этой главы.

С точки зрения компилятора простой констатации «это число 3» недостаточно. Разумеется, VB .NET, как и любой язык программирования, позволяет уточнить смысл литерала. Например, 31 — литерал типа Integer со значением 3, а литерал "3" относится к строковому типу String (тип String рассматривается ниже в этой главе; он несколько отличается от строкового типа в прежних версиях VB).

Примитивные типы можно рассматривать как атомарные элементы языка, хотя в VB .NET они представляют собой псевдонимы для классов из библиотеки System.

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

  • Byte: 1-байтовое целое без знака в интервале от 0 до 255.
  • Short: 2-байтовое целое со знаком в интервале от -32 768 до 32 767, аналог типа Integer в прежних версиях VB. Признаком типа Short в литералах является суффикс S — например, 237S.
  • Integer: 4-байтовое целое со знаком в интервале от -2 147 483 648 до 2 147 483 647, аналог типа Long в прежних версиях VB. Признаком типа Integer в литералах является суффикс I — например, 2371.

Если суффикс не указан, а число входит в интервал допустимых значений типа Integer, по умолчанию оно сохраняется в формате Integer. Это связано с тем, что на 32-разрядных процессорах тип Integer обрабатывается эффективнее остальных типов.

  • Long: 8-байтовое целое со знаком в интервале от -9 223 372 036 854 775 808 до 9 223 372 036 854 775 807. Не имеет аналогов в прежних версиях VB. Признаком типа Long в литералах является суффикс L — например, 2371.

При объявлении числовых переменных можно использовать старые суффиксы типов %, & и т. д. — например, литерал 1234% относится к типу Long. Но при этом следует помнить, что в VB6 и VB .NET эти суффиксы имеют разный смысл, поскольку тип Integer VB .NET соответствует типу Long V86. По этой причине использовать старый синтаксис не рекомендуется.

Любой целочисленный литерал можно записать в шестнадцатеричной системе счисления (по основанию 16), для чего он снабжается префиксом &Н. Например, литерал &HF соответствует десятичному числу 15, хранящемуся в формате Integer, поскольку суффикс типа не указан, а число входит в интервал допустимых значений типа Integer. Числа, записанные в восьмеричной системе счисления (по основанию 8), снабжаются префиксом &0.

При выполнении операций с вещественными числами используются следующие типы:

  • Single: 4-байтовое вещественное число. Признаком типа Single в литералах является суффикс F — например, 1.23F или 3F.
  • Double: 8-байтовое вещественное число. Если в числе с десятичной точкой не указан суффикс, по умолчанию оно сохраняется в формате Double. Это связано с тем, что Double работает эффективнее Single; на 32-разрядных процессорах Double является основным типом для выполнения вещественных операций. Признаком типа Double в литералах является суффикс R (или #).

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

  • Decimal: 12-байтовое вещественное число, гарантирующее отсутствие ошибок округления в громадном интервале допустимых значений с 28 значащими цифрами. Формальное определение гласит, что тип Decimal предназначен для хранения чисел с мантиссой в интервале ±79 228 162 514 264 337 593 543 950 335, масштабируемых до произвольного порядка при условии, что количество значащих цифр не превышает 28. Таким образом, наименьшее число, представляемое типом Decimal, равно ±0.0000000000000000000000000001. Признаком типа Decimal в литералах является суффикс D.

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

Console.WriteLine(12345678 * 4567)

компилятор выдает ошибку:

This constant expression produces a value that is not representable in type System.Integer.

Проблема решается при помощи суффикса типа Long:

Console.WriteLine(123456781 * 4567)

Общие методы MaxValue и MinValue, ассоциированные с типом, возвращают соответственно верхнюю и нижнюю границы интервала допустимых значений. Пример:

Console.WriteLine(Integer.MaxValue)

В табл. 3.2 собраны данные о соответствии числовых типов VB .NET, типов .NET Framework и их аналогов из VB6 (если они есть).

Таблица 3.2. Соответствие между числовыми типами

Тип VB. NET

Тип .NET Framework

Тип VB6

Byte

System. Byte

Byte

Boolean

System. Boolean

Boolean

Decimal

System. Decimal




Currency

Double

System. Double

Double

Short

System. Intl6

Integer

Integer

System.Int32

Long

Long

System.Int64


Single

System. Single

Single

 

Прочие литералы

Кроме числовых литералов также существуют литералы типов Boolean, Date и Char. Тип данных Bool ean принимает значения True и Fal se. В VB .NET он представляется 4 байтами (в отличие от 2 байт в VB6).

В VB .NET бета-версии 1 значение True было равно +1 (как и в других языках .NET). Начиная с бета-версии 2 оно снова стало равно -1. Говоря точнее, в поразрядных операциях и при преобразовании к числовым типам значение True равно -1, а не 1. Но если логическая величина VB .NET передается за пределы VB, при приведении к числовому типу нового языка она считается равной 1. Пожалуй, это решение было ошибочным, поскольку одной из целей, поставленных при разработке .NET, было обеспечение максимальной межъязыковой совместимости. Пока вы ограничиваетесь встроенными константами True и False, все будет нормально, но стоит перейти к конкретным числовым значениям — и у вас могут возникнуть проблемы.

Тип данных Date представляет дату и/или время. Как ИГ в VB5, такие литералы заключаются между символами #...# — например, #Jan 1. 2001#. Если время не указано), предполагается, что литерал соответствует полуночи указанной даты.

Тип Date в VB .NET не преобразуется к типу Double. В частности, из этого следует, что с датами нельзя производить математические вычисления — например, вычислить завтрашнюю дату командой Today+1.

Тип данных Char представляет один символ Unicode. Объем кодировки Unicode (65 536 символов) вполне достаточен для представления всех существующих алфавитов. Обычно символ заключается в кавычки, за которыми следует префикс С (например, "Н"С), но вы также можете воспользоваться встроенной функцией Chr и указать числовой код символа Unicode. Например, запись Chr(&H2153) представляет символ 1/3 кодировке Unicode, хотя в некоторых операционных системах этот символ не будет отображаться во время работы программы. Если заключить один символ в кавычки без суффикса «С», вы получите тип Stri ng вместо Char, а автоматическое преобразование между этими типами не поддерживается (команда Opti on Strict описана ниже в этой главе).

Объявление переменных

В VB .NET, как и в VB6, переменные объявляются в процедурах и функциях при помощи ключевых слов Dim и As, а присваивание выполняется знаком =:

Dim foo As String

foo = "bar"

Если вы не изменяли стандартную настройку VB .NET, переменные должны объявляться перед использованием (режим Option Explicit, впервые представленный в VB4, теперь используется по умолчанию). В VB .NET поддерживается инициализация переменных при объявлении. Пример:

Dim salesTax As Decimal = 0.0825D

Команда объявляет переменную с именем salesTax и присваивает ей начальное значение 0.0825 типа Decimal. При инициализации могут использоваться любые синтаксически правильные выражения VB .NET. Следующая команда присваивает переменной startAngle встроенное значение математической константы п, используя для этого константу класса System. Math: Dim startAngle As Decimal - Math.PI

Если переменная не была инициализирована при объявлении, ей присваивается стандартное значение, соответствующее ее типу, — например, числовым переменным присваивается 0. При таком удобном синтаксисе, как в VB .NET, всегда лучше инициализировать переменную при объявлении, чем полагаться на значение по умолчанию. В следующем фрагменте используется оператор &, применявшийся в VB6 для конкатенации строк:

Sub Main()

Dim salesTax As Decimal = 0.0825D

Dim state As String = "California"

Console.WriteLine("The sales tax in " & state & " is " & salesTax)

Console. ReadLine()

End Sub

Программа выводит следующий результат:

The sales tax in California is 0.0825

В отличие от предыдущих версий VB, объявление нескольких переменных в одной строке программы работает именно так, как подсказывает здравый смысл. Иначе говоря, следующая команда объявляет три переменные: i, j и k, относящиеся к типу Integer:

Dim i, j, k As Integer

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

Dim i, j, k As Integer = 1

Как и в прежних версиях VB, вместо указания типа с ключевым словом As может использоваться суффикс типа. Например:

Dim i%, myname$

Приведенная команда объявляет переменную i типа Integer (аналог Long в старом VB) и переменную myName типа String. Программистам VB .NET поступать подобным образом не рекомендуется.

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

Команды семейства DefType (например, Deflnt) в VB .NET не поддерживаются.

 

Преобразования разнотипных значений

По мнению многих программистов, прежние версии VB6 слишком либерально относились к преобразованию типов. В результате возникало явление «злостного искажения типов» — скажем, VB6 позволял умножить строковое представление числа на Integer.

В VB .NET предусмотрен режим жесткой проверки типов Option Strict. Чтобы активизировать его, включите следующую команду в начало программы (также можно воспользоваться флажком Strict Type Checking на вкладке Build диалогового окна Project Properties):

Option Strict On

При активизации этого режима (а это следует делать всегда!) VB .NET требует, чтобы любые преобразования типов, которые могут привести к потере данных, выполнялись явно. Например, при преобразовании Single к типу Integer может произойти потеря точности, поскольку тип Integer не позволяет представить весь интервал допустимых значений типа Single. С другой стороны, если потеря данных исключена (скажем, при преобразовании Integer в тип Long или Decimal), VB .NET выполняет преобразование автоматически. В документации VB .NET преобразования без потери данных называются расширяющими преобразованиями (widening conversions). В табл. 3.3 переделены допустимые расширяющие преобразования для базовых типов данных.

Таблица 3.3. Допустимые расширяющие преобразования для базовых типов VB .NET

Тип

Допустимое расширение

Byte Byte, Short, Integer, Long, Decimal Single, Double
Short Short, Integer, Long, Decimal, Single, Double
Integer Integer, Long, DecimaL Single, Double
Long Long, DecimaL Single, Double
Single Single, Double

Date

Date, String

Более того, при активном режиме жесткой проверки типов вы не сможете использовать конструкции вида:

Dim foo As Boolean

foo = 3

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

Dim foo As Boolean

foo =СВооl(З)

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

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

Option Strict Off

Впрочем, поступать подобным образом не рекомендуется.

Если содержимое переменной одного типа может быть преобразовано к другому типу, можно воспользоваться функцией явного преобразования, как в только что приведенном примере с СВооl. Функции явного преобразования типов перечислены в табл. 3.4.

Таблица 3.4. Функции явного преобразования типов

Функция

Описание

CBool Преобразует выражение к типу Boolean
CByte Преобразует выражение к типу Byte
CInt Преобразует выражение к типу Integer с округлением
CIng Преобразует выражение к типу Long с округлением
CSng Преобразует выражение к типу Single

CDate

Преобразует выражение к типу Date

 

Функция

Описание

СDbl Преобразует выражение к типу Double
CDec Преобразует выражение к типу Decimal
CStr Преобразует выражение к типу String

CChar

Преобразует первый символ строки к типу Char

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

На первый взгляд кажется, что тип Char можно интерпретировать как короткое целое без знака (то есть целое в интервале от 0 до 65 535), но делать этого не следует. Начиная с бета-версии 2 было запрещено преобразование Char в число функциями семейства CInt; вместо этого используется встроенная функция Asc.

Тип object и исчезновение типа Variant

Вероятно, вы заметили, что при описании типов нигде не упоминается тип Variant. BVB .NET этот тип не поддерживается — и это очень хорошо! В VB6 переменные Variant допускали хранение данных произвольного типа. Программисты часто злоупотребляли этой возможностью, что приводило к возникновению нетривиальных ошибок в программах. В VB .NET все типы данных (даже числовые, как Integer) являются частными случаями типа Object. Может показаться, что тип Object стал аналогом Variant в VB .NET, но это не так. Как будет показано в главах 4 и 5, тип Object занимает в программировании .NET значительно более важное место и обладает множеством интересных возможностей. Мы вернемся к типу Object в главах 4 и 5.

Ниже приведен хрестоматийный пример — преобразование температуры по Цельсию в температуру по шкале Фаренгейта. Мы руководствуемся следующими предположениями:

  1. Пользователь завершает ввод текста нажатием клавиши Enter.
  2. Все введенные символы воспринимаются методом ReadLine().
  3. Пользователь ввел число, поэтому введенный текст преобразуется к числовому типу функцией CDec (конечно, на практике введенные данные следовало бы предварительно проанализировать):

' Преобразование температуры по Цельсию в температуру по Фаренгейту

Option Strict On Module

Modulel Sub Main()

Dim cdeg As Decimal

Console. Writer Enter the degrees in centigrade...")

cdeg = CDec(Console.ReadLine())

Dim fdeg As Decimal

fdeg = (((9@ / 5) * cdeg) + 32)

Console.WriteLine(cdeg & " is " & fdeg & " degrees Fahrenheit.")

Console. ReadLine()

End Sub

End Module

Обратите внимание на суффикс @ — он гарантирует, что при вычислениях будет использоваться тип Decimal. Если убрать этот суффикс, то при включенной жесткой проверке типов будет выдано сообщение об ошибке!

При использовании простого оператора / для деления в VB .NET необходимо учитывать некоторые нюансы. За дополнительной информацией обращайтесь к разделу «Математические операторы».

Строки

Строковая переменная содержит текст в кодировке Unicode длиной до 231 (более 2 миллиардов!) символов. Как было показано выше, значения строкового типа заключаются в кавычки:

Dim message As String

message = "Help"

Конкатенация (объединение) строк обычно выполняется оператором &. Старый вариант с оператором + тоже работает, но при отключении жесткой проверки типов он может вызвать серьезные проблемы, поэтому использовать знак + при конкатенации не рекомендуется. Старый способ идентификации строковых переменных с суффиксом $ (например, aStringVariableS) иногда используется для временных переменных.

В VB .NET строковые переменные не относятся к базовому типу, а являются экземпляра-ми класса String. Некоторые нюансы, связанные с их применением, будут рассмотрены в главе 4, а пока мы упомянем лишь одну особенность, о которой необходимо знать для эффективной работы со строками в VB .NET: при любой модификации строки в VB .NET создается новый экземпляр строки. Частая модификация строки требует больших затрат ресурсов, поэтому в VB .NET имеется класс StringBuilder для выполнения подобных операций (например, выборки данных из буфера и объединения их в строковой переменной).

В отличие от предыдущих версий VB, в VB .NET не поддерживаются строки фиксированной длины.

 

Строковые функции

В вашем распоряжении остались все классические строковые функции VB6 (Left, Right, Mid и т. д.), но версии этих функций с суффиксом $ теперь не поддерживаются. В табл. 3.5 перечислены важнейшие функции класса String, заменяющие строковые функции VB6. Не забывайте, что при многократной модификации строк (например, при вызове Mid в цикле) следует использовать класс StringBuilder, описанный в главе 4. Некоторые из приведенных методов используют массивы, которые будут рассмотрены ниже в этой главе.

При программировании для .NET рекомендуется по возможности использовать методы и свойства класса Stri ng, входящего в .NET Framework. Самые распространенные строковые методы перечислены в табл. 3.6.

Таблица 3.5. Основные строковые функции

Функция

Описание

Asc

Возвращает код первого символа в строке

Chr

Преобразует число в символ Unicode

Filter

Получает строковый массив и искомую строку; возвращает одномерный массив всех элементов, в которых был найден заданный текст

GetChar

Возвращает символ строки с заданным индексом в формате Char. Индексация символов начинается с 1. Например, команда GetChar("Hello",2) возвращает символ «е» в виде типа Char

InStr

Возвращает позицию первого вхождения одной строки в другой строке

InStrRev

Возвращает позицию последнего вхождения одной строки в другой строке

Join

Строит большую строку из меньших строк

LCase

Преобразует строку к нижнему регистру

Left

Находит или удаляет заданное количество символов от начала строки

Len

Возвращает длину строки

LTrim

Удаляет пробелы в начале строки

Mid

Находит или удаляет символы в строке

Replace

Заменяет одно или более вхождений одной строки в другой строке

Right

Находит или удаляет заданное количество символов в конце строки

RTrim

Удаляет пробелы в конце строки

Space

Генерирует строку заданной длины, состоящую из пробелов

Split

Позволяет разбивать строку по заданным разделителям (например, пробелам)

Str

Возвращает строковое представление числа

StrComp

Альтернативный способ сравнения строк

StrConv

Преобразует строку из одной формы в другую (например, с изменением регистра)

String

Создает строку, состоящую из многократно повторяющегося символа

Trim

Удаляет пробелы в начале и конце строки

UCase

Преобразует строку к верхнему регистру

 

Таблица З.6. Основные строковые методы и свойства .NET Framework

Метод/свойство

Описание

Chars Возвращает символ, находящийся в заданной позиции строки
Compare Сравнивает две строки
Copy Копирует существующую строку
Copy To Копирует заданное количество символов, начиная в заданную позицию массива символов
Empty Константа, представляющая пустую строку
EndsWith Проверяет, завершается ли заданная строка определенной последовательностью символов
IndexOf Возвращает индекс первого вхождения подстроки в заданной строке

Метод/свойство

Описание

Insert

Возвращает новую строку, полученную вставкой подстроки в заданную позицию

Join

Объединяет массив строк с заданным разделителем

LastlndexOf

Возвращает индекс последнего вхождения заданного символа или подстроки в строке

Length

Возвращает количество символов в строке

PadLeft

Выравнивает символы строки по правому краю. Строка дополняется слева пробелами или другими символами до заданной длины

PadRight

Выравнивает символы строки по левому краю. Строка дополняется справа пробелами или другими символами до заданной длины

Remove

Удаляет из строки заданное количество символов, начиная с заданной позиции

Replace

Заменяет все вхождения подстроки другой подстрокой

Split

Разбивает строку, превращая ее в массив подстрок

Starts With

 

Проверяет, начинается ли заданная строка определенной последовательностью символов

Substring

Возвращает подстроку, начинающуюся с заданной позиции

ToCharArray

Копирует символы строки в символьный массив

ToLower

Возвращает копию строки, преобразованную к нижнему регистру

ToUpper

Возвращает копию строки, преобразованную к верхнему регистру

Trim

Удаляет пробелы или все символы из набора, заданного в виде массива символов Unicode, в начале и конце строки

TrimEnd

Удаляет пробелы или все символы из набора, заданного в виде массива символов Unicode, в конце строки

TrimStart

Удаляет пробелы или все символы из набора, заданного в виде массива символов Unicode, в начале строки

 

В отличие от VB6, где индексация символов в строке начиналась с 1, в методах .NET Framework индекс первого символа равен 0.

Поскольку в .NET Framework строки являются объектам, синтаксис вызова этих методов достаточно логичен и удобен. Выполните следующую программу:

Sub Main()

Dim river As String =" Mississippi Missippi"

'один пробел слева

Consol e. Wri teLi ne( ri ver. Tollpper ())

Console.Wri teLi net ri ver.ToLower())

Console.WriteLineCriver.Trim())

Console. WriteLinetri ver. EndsWith("I"))

Consol e.Wri teLi ne С ri ver.EndsWith("i"))

Console.WriteLine(river.IndexOf("s"))

'Индексация начинается с 0!

Console.WriteLineCriver.Insert(9. " river"))

'Индексация

' начинается с 0!

Consol e.ReadLine() End Sub

Результат выглядит так:

MISSISSIPPI MISSIPPI

mississippi missippi

Mississippi Missippi

False

True

3

Mississi riverppi Missippi

Форматирование данных

Все функции форматирования возвращают новую строку в заданном формате. В VB .NET сохранены аналоги старых функций форматирования из VB6 и VBScript, поэтому вы можете продолжать использовать функции Format, Format Number, For-matCurrency, FormatPercent и FormatDateTime. Последние четыре функции неплохо справляются с простым форматированием, но мы все равно предпочитаем использовать более мощные средства форматирования, реализованные в .NET Framework.

Синтаксис форматирования в .NET Framework на первый взгляд выглядит несколько странно. Рассмотрим несложный пример:

Dim balance As Decimal = 123456

Dim creditLimit As Decimal = 999999

Console.WriteLine("Customer balance is {0:C}, credit limit is {1:C} ",_

balance. creditLimit = balance)

Результат:

Customer balance is $123,456.00. credit limit is $876.543.00

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

Console.WriteLine("Customer credit is {1:C}, balance is {0:C} ".

balance. creditLimit = balance)

Вы получите следующий результат:

Customer credit is $876.543.00. balance is $123.456.00

Форматируемые переменные перечисляются в порядке их следования в списке. Так, во втором примере {1:С} означает вторую переменную в списке, а {0:С} соответствует первой переменной (напомним, что индексация в .NET Framework начинается с 0). «С» означает форматирование в денежном формате, определенном в параметрах локального контекста Windows.

Математические операторы

В табл. 3.7 приведены условные обозначения шести базовых математических операций.

Результат стандартного деления (/) всегда относится к типу Double, даже в случае де-ления без остатка. Результат целочисленного деления (\) всегда относится к типу Integer. Это означает, что при работе с типами Decimal и Integer вам придется часто использовать функции преобразования.

Таблица 3.7. Математические операции

Оператор

Операция

+ Сложение
- Вычитание (и обозначение отрицательных чисел)
/ Деление (преобразование к Double — не может вызвать исключение DivideByZero; см. главу 7)
\ Целочисленное деление (без преобразования — может вызвать исключение DivideByZero)
* Умножение
^ Возведение в степень

Чтобы лучше разобраться в разных типах деления, можно воспользоваться методом .NET GetType. В командах вывода (таких как WriteLine) этот метод возвращает имя типа в строковом представлении. Рассмотрим следующую программу:

Module Modulel

Sub Main()

Console.WriteLine((4 / 2).GetType())

Console. ReadLine()

End Sub

End Module

В консольном окне выводится строка

System.Double

Возможности метода GetType не ограничиваются простым выводом имени — в частности, он используется в процессе рефлексии. Механизм рефлексии описан в главе 4.

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

Option Strict On

Module Modulel Sub Main()

Dim cdeg As Decimal

Console.. Writer Enter the degrees in centigrade...")

cdeg=CDec(Console.ReadLine())

Dim fdeg As Decimal

fdeg = (((9 / 5) * cdeg) + 32)

Console.WriteLine(cdeg & " is " & fdeg & " degrees Fahrenheit.")

Console. ReadLine()

End Sub

End Module

Из-за присутствия знака / в выделенной строке переменной fdeg присваивается результат типа Double. В режиме жесткой проверки типов это приводит к тому, что на стадии компиляции будет выдано следующее сообщение об ошибке:

Option Strict disallows implicit conversions from Double to Decimal.

Как исправить ошибку? Только не надо убирать команду Option Strict — это одно из лучших новшеств VB .NET, которое избавляет вас от злостного искажения типов. Лучше воспользуйтесь суффиксом @ или преобразуйте выражение (полностью или частично) к типу Decimal. Пример:

fdeg = ((CDec(9 / 5) * cdeg) + 32)

Поскольку результат деления преобразуется к типу Decimal, результат тоже относится к типу Decimal.

Остается лишь заметить, что в этом простом примере мы используем метод Write вместо Wri teLi ne, чтобы предотвратить перевод строки после вывода текста. Кроме того, в реальной программе введенные данные следовало бы предварительно проанализировать, потому что пользователи часто ошибаются при вводе.

Наконец, вещественное деление в VB .NET соответствует стандарту IEEE, поэтому вместо ошибки деления на ноль теперь происходит нечто странное. Пример:

Sub Main()

Dim getData As String

Dim x, у As Double

x = 4

У = 0

Console.WriteLine("What is 4/0 in VB .NET? " & x / y)

Console.ReadLine()

End Sub

Результат выглядит так:

What is 4/0 in VB. NET? Infinity

Результат деления 0/0 равен

NaN (Not A Number, «не является числом»).

В табл. 3.8 перечислены операторы, используемые только при делении чисел типа Integer и Long.

Таблица 3.8. Математические операторы целочисленного деления

Оператор

Операция

\

Целочисленное деление любых целых чисел

Mod

Остаток от целочисленного деления

Оператор \ игнорирует остаток от деления и возвращает результат типа Integer (если он относится к интервалу допустимых значений этого типа). Например, 7\3=21. Напомним, что оператор / дает результат типа Double; если вы хотите, чтобы частное относилось к типу Integer — воспользуйтесь оператором \ или функцией преобразования типа.

Оператор Mod дополняет оператор целочисленного деления и возвращает остаток от целочисленного деления. Например, 7 Mod 3 = 1. Если целые числа делятся без остатка, оператор Mod возвращает 0: 8 Mod 4 = 0.

Круглые скобки и приоритет операций

При обработке сложных выражений последовательность выполнения операций задается двумя способами. При использовании круглых Скобок вам не придется запоминать приоритеты различных операций. В VB .NET, как и во многих языках программирования, операции обладают приоритетом, определяющим последовательность их выполнения. Умножение обладает более высоким приоритетом, чем сложение; следовательно, выражение 3+4*5 равно 23, поскольку умножение (4*5) выполняется раньше, чем сложение.

Ниже перечислены математические операции в порядке убывания приоритета.

  1. Возведение в степень (^).
  2. Унарный минус (изменение знака числа).
  3. Умножение и деление.
  4. Целочисленное деление.
  5. Вычисление остатка (Mod).
  6. Сложение и вычитание.

Если две операции обладают одинаковым приоритетом, порядок выполнения определяется порядком их следования в выражении (слева направо).

Сокращенная запись операций с присваиванием

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

Сокращенная запись

Эквивалент

А*=В

А = А*В

А+=В

А = А + В

А/=В

А = А/В

А-=В

А = А-В

А\=В

А = А\В

А^=В

А = А^В

А&=В

А = А & В (конкатенация строк)

 

Математические функции и математические константы

Встроенные математические функции VB6 работают и в VB .NET, но мы предпочитаем использовать методы класса Math, входящего в .NET Framework. В этот класс также входят некоторые полезные константы (например, Math. PI и Math. Е). Основные математические функции класса Math перечислены в табл. 3.9. Все эти функции объявлены общими (shared), поэтому они принадлежат классу Math в целом, а не его отдельным экземплярам (которые, впрочем, все равно невозможно создать — см. главу 4).

Все перечисленные методы являются общими методами класса Math, поэтому они должны вызываться с префиксом Math — например, Math.Log10(l0).

В VB .NET предусмотрена целая группа методов для получения разнообразных случай-ных чисел. Мы рассмотрим эти методы в главе 4, когда речь пойдет о создании объектов.

Таблица 3.9. Общие математические функции класса Math

Математическая функция

Описание

Abs

Возвращает абсолютное значение (модуль) числа

Acos

Возвращает угол, косинус которого равен заданному числу

Asin

Возвращает угол, синус которого равен заданному числу

Atan

Возвращает угол, тангенс которого равен заданному числу

Ceiling

 

Возвращает наименьшее целое число, большее либо равное заданному числу

Cos

Возвращает косинус заданного угла

Exp

Возвращает число е (приблизительно 2,71828182845905), возведенное в заданную степень

Floor

Возвращает наибольшее целое число, большее либо равное заданному числу

Log

Возвращает натуральный логарифм

Log10

Возвращает десятичный логарифм

Max

Возвращает большее из двух заданных чисел

Min

Возвращает меньшее из двух заданных чисел

Round

Возвращает целое число, ближайшее к заданному числу

Sign

Возвращает величину, определяющую знак числа

- Sin

Возвращает синус заданного угла

Sqrt

Возвращает квадратный корень

Tan

Возвращает тангенс заданного угла

 

Константы

VB .NET позволяет создавать именованные константы для значений, остающихся постоянными на протяжении всей работы программы. Константы объявляются по аналогии с переменными, а их имена подчиняются тем же правилам: до 255 символов, начинаются с буквы, после которой следует произвольная комбинация букв, цифр и символов подчеркивания. В книге имена констант записываются прописными буквами.

В VB .NET при активизации жесткой проверки типов необходимо явно указывать тип констант:

Const PIE = 3.14159 ' Не будет компилироваться с Option Strict

Const PIE As Double = 3.14159 ' Правильно, но Math.PI лучше :-)

Значение констант может определяться числовыми выражениями, в том числе и содержащими ранее определенные константы:

Const PIE_OVER_2 As Double = PIE / 2

Аналогичным образом определяются строковые константы:

Const USER_NAME As String = "Bill Gates"

.NET Framework содержит немило встроенных, заранее определенных глобальных констант, которые вы можете использовать в своих программах. Многие из них аналогичны константам VB6 с префиксом vb, но они являются членами различных классов, поэтому обращения к ним выглядят несколько иначе. Например, константа vbCrLf в VB .NET принадлежит классу ControlChars, поэтому при обращении к ней используется запись Control Chars. CrLf.

Циклы

В VB .NET, как практически во всех языках программирования, существуют циклы — конструкции, позволяющие выполнять операции заданное количество раз или продолжать, пока выполняется (или наоборот, не выполняется) некоторое логическое условие. По сравнению с прежними версиями VB синтаксис циклов мало изменился. В частности, изменилась конструкция While/Wend, но это изменение к лучшему.

Цикл с определенным условием

Цикл, выполняемый заданное количество раз, определяется при помощи ключевых слов For и Next. Например, следующая программа выводит в консольном окне числа от 1 до 10:

Sub Main()

Dim i As Integer

For i = 1 To 10

Console.WriteLine(i)

Next 1

Console.ReadLine()

End Sub

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

Хотя в качестве счетчика может использоваться числовая переменная любого типа, ре-комендуется использовать переменные типа Integer. В этом случае VB .NET тратит минимальное количество времени на изменение счетчика, что ускоряет выполнение цикла.

Единичное приращение счетчика, используемое по умолчанию, иногда неудобно—в некоторых ситуациях счетчик должен изменяться на 2, на дробную величину или в обратном направлении. Как и во всех прежних версиях VB, нестандартное приращение указывается в цикле For-Next с ключевым словом Step.

Следующая программа имитирует обратный отсчет перед запуском космического корабля:

Sub Main()

Dim i As Integer

For i = 10 To 1 Step =1

Console.WriteLine("It's t minus " & i & " and counting.")

Next i

Console.WriteLine("Blastoff!")

Console. ReadLine()

End Sub

При отрицательном приращении тело цикла For-Next игнорируется в том случае, если начальное значение счетчика меньше конечного. Это очень удобно при выполнении таких операций, как удаление элементов из списка. Если бы отсчет велся от 0 до ListCount, то на середине произошло бы обращение к удаленному элементу, тогда как при отсчете от ListCount до 0 с шагом -1 элементы нормально удаляются от последнего к первому.

Значение Step может относиться к любому числовому типу. Пример:

for yearlylnterest = .07 То .09 Step .00125D

Цикл перебирает значения от 7 до 9 процентов с приращением в 1/8 процента. Обратите внимание на использование типа Decimal для предотвращения ошибок округления.

VB .NET, как и прежние версии VB, позволяет создавать вложенные циклы практически неограниченной глубины. Следующий фрагмент выводит таблицу умножения с простейшим форматированием:

Sub Main()

Dim i, j As Integer

For j = 2 To 12

For i = 2 To 12

Console.Writed * j & " ")

Next i

Console. WriteLine()

Next j

Console ReadLine()

End Sub

Во внутреннем цикле вместо метода WriteLine используется метод Write, чтобы избежать перевода строки при выводе соседних элементов.

Циклы с неопределенным условием

Довольно часто условие продолжения цикла зависит от результатов, полученных в теле цикла. Следующая конструкция используется в VB .NET для построения цикла с неопределенным условием, тело которого выполняется минимум один раз (завершающая проверка):

Do

' Команды VB .NET (0 и более)

Until условие_выполняется

Конечно, условие не ограничивается простой проверкой равенства. В вашем распоряжении операторы сравнения, перечисленные в табл.3.10.

Таблица 3.10. Операторы сравнения

Символ

Проверяемое условие

<>

Не равно

<

Меньше

<=

Меньше или равно

>

Больше

>=

Больше или равно

Строковые операнды по умолчанию сравниваются в соответствии с порядком символов Unicode. Таким образом, «А» предшествует «В», но «В» предшествует «а» (а пробел предшествует любому печатному символу). Строка «aBCD» предшествует строке «CDE» (то есть считается «меньше» ее), поскольку прописные буквы в кодировке стоят раньше строчных.

Как и в VB6, вы можете игнорировать регистр символов во всех сравнениях модуля или формы; для этого в начало модуля или формы включается команда Option Compare Text. Команда Option Compare Binary возвращается к стандартному сравнению строк в соответствии с положением символов в кодировке ANSI. При активном режиме Option Compare Text используется порядок символов для страны, указанной при установке системы Windows.

Ключевое слово Unti 1 можно заменить ключевым словом Whi I e (при этом следует заменить условие на противоположное). Например, фрагмент

Do

' Команды VB .NET (0 и более)

Loop Until X <> String.Empty

эквивалентен следующему фрагменту:

Do

' Команды VB .NET (0 и более)

Loop While X = String.Empty

Обратите внимание на использование константы String.Empty вместо пустой строки "", менее наглядной и чаще приводящей к ошибкам. Если переместить ключевое слово Whi 1е или Unti 1 в секцию Do, проверка будет выполняться в начале цикла (и при ложном условии цикл не будет выполнен ни одного раза). Пример:

Do While Text1.Text <> String.Empty

' Обработать непустой текст Loop

Условия объединяются при помощи операторов Or, Not и And. Пример:

Do While count < 20 And savings < 1000000

Если вы предпочитаете использовать старую конструкцию While-Wend, учтите, что клю-чевое слово Wend было заменено командой End While.

Условные команды и принятие решений

" В VB .NET условная команда If, как и в VB6, существует в двух версиях — однострочной и многострочной:

If X < 0 Then Console.WriteLine("Number must be positive!")

Условие конструкции If-Then может содержать логические операторы And, Or и Not. Довольно часто программа выполняет разные действия в зависимости от того, окажется ли условие истинным или ложным. В этом случае базовая форма команды

If-Then:

If условие Then

' Команды VB .NET (0 и более) End If

дополняется одной или несколькими секциями El se:

If условие Then

' Команды VB .NET (0 и более) Else

' Команды VB .NET (0 и более)

End If

Несколько последовательных проверок в секциях Else можно оформить в виде конструкции Elself:

If условие Then

' Команды

Elself условие Then

' Команды

Elself условие Then

' Команды

Else

' Команды

End If

Конструкция If-Then может использоваться для преждевременного выхода из цикла — для этого она объединяется с командой Exit Do или Exit For. Встретив команду Exit Do или Exit For, VB .NET немедленно завершает цикл и продолжает выполнение программы с команды, следующей за ключевым словом Loop или Next (в зависимости от типа цикла).

Изменения в видимости переменных

Область видимости переменных и методов в VB .NET определяется по более сложным правилам, чем в прежних версиях VB. Эта тема подробно описана в главах 4 и 5. В частности, изменения проявляются при объявлении переменных в теле цикла или блока If-Then. Такие переменные невидимы за пределами блока, в котором они были объявлены. Например, в следующем фрагменте мы выбираем одну из двух версий строковой переменной Ri sk и затем пытаемся использовать ее:

If income < 100000 Then

Dim risk As String = "too much risk" Else

Dim risk As String = "love to make a deal"

End If

Console.WriteLine("Your risk level is " & Risk)

На экране появляется сообщение об ошибке:

The name 'risk' is not declared.

Видимость обеих версий переменной risk ограничивается блоком, в котором они были объявлены! Мораль: не объявляйте переменные внутри блоков, если для этого нет веских причин.

Ускоренная проверка

Если компилятор обнаруживает, что проверенная часть сложного логического условия однозначно определяет результат, он не проверяет остаток выражения. Это называется ускоренной проверкой (short curcuiting). Например, если в следующем примере переменная foo ложна, компилятор не проверяет переменную bar:

If foo And bar Then...

Так было в VB .NET бета-версии 1, но в прежних версиях VB ускоренная проверка не применялась. После многочисленных жалоб разработчики Microsoft вернули старую интерпретацию логических операторов And и Or и добавили новые ключевые слова AndAlso и OrElse, поддерживающие ускоренную проверку:

If foo AndAlso Then...

Select Case

В качестве альтернативы для громоздких конструкций с множеством Elself в VB .NET была сохранена команда Select Case, упрощающая принятие решений в зависимости от состояния числовой или строковой переменной. Пример:

Select Case average

Case Is > 90

Console.WriteLine("A")

Case Is > 80

Console. Wri teLi ne("B")

Case Is > 70

Console.WriteLine("C")

Case Else

Console.WriteLine("You fail")

End Select

Программисты с опытом работы на С и Java, обратите внимание — команда break не нужна, поскольку выполняется только одна секция Case. Дискретные наборы значений перечисляются через запятую, а ключевое слово То позволяет задавать интервалы:

Select Case yourChoice

Case 1 To 9

' Порядок

Case -1. 0

' Неправильный ввод

End Select

GoTo

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

Частое использование GoTo приводит к многократным передачам управления и порождает «спагетти-код», который трудно читать и отлаживать. С другой стороны, в некоторые ситуациях применение GoTo делает программу более понятной и логичной — например, если в какой-то ситуации потребовалось выйти сразу из нескольких вложенных циклов. Команда Exit для этого не подходит, поскольку она завершает только текущий цикл.

В данной ситуации вместо Goto можно воспользоваться перехватом исключений (см. главу 7), но некоторые программисты предпочитают классический подход.

Чтобы воспользоваться командой GoTo в VB .NET, необходимо присвоить метку соответствующей строке. Метка начинается в первой позиции строки, ее первым символом является буква, а последним — двоеточие. Старайтесь присваивать меткам содержательные имена. Пример:

Bad-Input:

' Фрагмент, выполняемый при переходе

Предположим, в нашей программе данные вводятся во вложенном цикле For. Чтобы завершить ввод, пользователь вводит ZZZ:

SubMain()

Dim getData As String

Dim i, j As Integer

For i = 1 To 10

For j = 1 To 100

Console.Write("Type the data, hit the Enter key between " & _

"ZZZ to end: ") getData = Console. ReadLine()

If getData = "ZZZ" Then

Goto Bad Input Else

' Обработка данных

End If

Next j

Next i

Exit Sub

BadInput:

Console.WriteLine("Data entry ended at user request")

Console. ReadLine()

End Sub

Выходить из вложенного цикла командой Exit For неудобно — нам пришлось бы писать дополнительный код для выхода из внешнего цикла. Обратите внимание: команда Exi t Sub предотвращает передачу управления помеченному коду после завершения обоих циклов.

Логические операторы

Начиная с бета-версии 2 логические операторы (Not, And, Or и т. д.) работают на уровне двоичных разрядов, как и в прежних версиях VB. Допустим, у вас имеются два целых числа X и Y. Каждый бит результата X And Y равен 1 лишь в том случае, если равны 1 соответствующие биты обоих операндов; в противном случае бит результата равен нулю. Таким образом, при вычислении результата X And Y вычисляется каждый бит 32-разрядного целого числа. Пример:

X = 7 'В двоичном представлении = 0111

Y = 12 'В двоичном представлении = 1100

Выражение X And Y в двоичной системе равно 0100 (4 в десятичной системе), поскольку лишь во второй позиции оба бита равны 1. Остальные биты результата равны 0, поскольку в этих позициях хотя бы один из битов операндов равен 0. Этот способ позволяет проверить значения отдельных битов целого числа. Примеры:

(X And 1) = 1: проверить, установлен ли младший бит числа.

(X And 2) о 2: проверить, установлен ли предпоследний бит числа (поскольку в

двоичной системе число 2 представляется записью 10).

X And 255: младший байт числа (255 дес. = 11111111 дв.).

X And 65280: старший байт числа (65280 дес. = 1111111100000000 дв.).

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

Массивы

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

Массивы VB .NET во многом отличаются от массивов VB6. Одни изменения видны сразу, другие не столь очевидны. Наиболее заметные изменения перечислены ниже.

  • Индексация-элементов в массивах начинается с 0. На момент написания книги ключевое слово То не поддерживалось — будем надеяться, что оно еще вернется!

    Начиная с бета-версии 2 объявление 01m stri ngLi st(7) создает массив из восьми элементов с индексами от 0 до 7. Поскольку в VB .NET индексация всегда начинается с нуля, третий элемент массива обозначается stri ngList(2), а предшествующие элементы обозначаются stringList(0) и stringList(l).

  • Все массивы VB .NET являются динамическими. Во время работы программы их можно переобъявить с новым размером при помощи команд ReDim (с потерей текущего содержимого) и ReDim Preserve (с сохранением текущего содержимого). Пример:

    Dim x() As Single

    ReDim x(20) ' Начиная с бета-версии 2. создает массив из 21 элемента

    ReDim Preserve x(50) ' 21 элемент сохраняется в массиве.

Команда ReDim не позволяет изменять тип массива; также не допускается использование ReDim при объявлении. Перед вызовом ReDim массив должен быть объявлен при помощи Dim или аналогичной команды.

  • Массивы могут инициализироваться при объявлении, как показывает следующий пример:

Dim weekend() As String = {Saturday. Sunday}

Менее очевидные изменения обусловлены тем, что массивы VB .NET являются экземплярами класса Array. Подробности будут рассмотрены в главе 4, а пока достаточно указать, что это позволяет выполнять операции с массивами вызовом методов класса Array. Ниже продемонстрирован пример сортировки массива методом Sort:

Sub Main()

Dim stuff() As Integer = (9. 7, 5, 4, 2. 1, -37, 6}

Array.Sort(stuff)

Dim i As Integer

For i = 0 To UBound(stuff)

Console.WriteLine(stuff(i))

Next

Console. ReadLine()

End Sub

Программа выводит массив, отсортированный с применением чрезвычайно эффективного алгоритма «быстрой сортировки».

VB.NET наследует от .NET Framework некоторые очень полезные структуры данных, возможности которых выходят далеко за рамки обычных массивов. На фоне этих структур коллекции VB5 и последующих версий выглядят примитивно. В частности, списковые массивы (с динамически изменяемыми размерами) и ассоциативные массивы (с доступом к данным по ключу) часто оказываются удобнее обычных массивов. Многие из новых структур данных рассматриваются в главах 5 и 6.

Массивы с индексацией элементов в заданном интервале

Утверждение о том, что индексация массивов всегда начинается с 0, не совсем точно. Теоретически можно определять массивы с заданной верхней и нижней границей индекса, но из-за неудобного синтаксиса и снижения быстродействия вряд ли вам захочется это делать. В следующем фрагменте создается массив с индексацией элементов от 1995 до 2002:

Sub Main()

Dim anArray As Array

Dim i As Integer

Dim i(0) As Integer

Dim lowerBounds(0) As Integer

i(O) = 7

lowerBounds(0) = 1995 ' Создать массив с индексами 1995 - 2002

аnАrrау = Array.CreateInstance(GetType(System.Int32). 1. lowerBounds) anArray.SetValue(200000, 1995) anArray.SetValue(1000000. 2001)

Console.WriteLine("The entry in position 1995 is " & _ (anArray.GetValue(1995).ToString))

Console.WriteLine("The entry in position 2002 is " & _ (anArray.GetValue(2001).ToString))

Console. ReadLine()

End Sub

Присваивание выполняется методом SetValue (значение,индекс), а чтение — методом GetValue(индекс). Но если массив создается подобным образом в режиме жесткой проверки типов, вам придется позаботиться о том, чтобы присваиваемое значение было преобразовано к правильному типу!

Цикл For-Each

Содержимое массива часто перебирается в цикле от 0 до UBound(массив), однако вы также можете воспользоваться конструкцией For-Each. Синтаксис For-Each выглядит следующим образом:

For Each переменная In массив

[команды]

[Exit For при необходимости]

[команды] Next

Конструкция For-Each универсальна и может использоваться в тех случаях, когда структура данных поддерживает итеративный перебор элементов. За подробностями обращайтесь к главе 4.

Microsoft утверждает, что применение For-Each не будет приводить к существенному снижению быстродействия по сравнению с For-Next (как это было в VB6).

Многомерные массивы

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

Dim mulTable(11.11) As Integer

' Создает массив 12x12

Dim i As Integer, j As Integer

For i = 0 To 11

For j = 0 To 11

mulTable(i.j) = (i+l)*(j+l)

Next j

Next i

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

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

Dim salesByDivision( , , ) As Decimal

Команда ReDim задает или изменяет количество элементов в каждом измерении, но размерность массива не изменяется.

При сохранении содержимого массива командой ReDim Preserve допускается изменение количества элементов только в последнем измерении массива.

Процедуры и функции

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

В VB .NET, как и во многих языках программирования, существуют два способа передачи параметров функциям и процедурам: передача по ссылке и передача по значению. Когда параметр передается по ссылке, его изменения внутри функции приведут к изменению исходного аргумента после выхода из функции. По умолчанию в VB .NET параметры передаются по значению (а в VB6 — по ссылке).

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

Функции

Чтобы создать новую функцию или процедуру в окне программы, установите курсор за пределами других процедур и функций и начинайте вводить заголовок процедуры или функции. Как только вы нажмете клавишу Enter, редактор IDE автоматически создаст команду End правильного типа (End Functi on или End Sub). Ниже приведен заголовок функции, которая получает целый параметр по значению и возвращает логическую величину (True или False) в зависимости от того, принадлежит ли переданный параметр интервалу от 1 до 10: Function IsBetweenlAnd10(ByVal num As Integer) As Boolean

В режиме жесткой проверки типов (Option Strict) при объявлении функции необходимо указывать тип возвращаемого значения (в нашем примере — Boolean).

Полный текст модуля с функций Is Between lAnd 10 приведен ниже. Порядок следования функций не важен — функция Sub Mai n может находиться и после определения функции, которая в ней используется.

Module Modulel

Function IsBetweenlAnd10 (ByVal num As Integer) As Boolean

If num >= 1 And num <=10 Then

Return True

Else

Return False

End If

End Function

Sub Main()

Console. WriteLinedsBetweenlAnd100))

Console. ReadLine()

End Sub

End Module

В VB .NET при вызове функции или процедуры непустой список параметров всегда заключается в круглые скобки, как в строке с вызовом Console.WriteLine: IsBetweenlAnd100)

Обратите внимание на ключевое слово Return. При выполнении команды Return функция завершается и возвращает значение, указанное после Return (значение должно быть определенным — возвращение аналога voi d не допускается). Также поддерживается синтаксис с присваиванием имени функции, использовавшийся в прежних версиях VB:

Function IsBetweenlAnd10(ByVal num As Integer) As Boolean

If num >= 1 And num <= 10 Then

IsBetweenlAnd10 = True Else

IsBetweenlAnd10= False

End If

End Function

Использование Return — дело вкуса. Команда Return нагляднее и проще, но старый синтаксис оставляет управление внутри функции, а это иногда бывает удобно.

Обобщенная форма определения функции выглядит следующим образом:

Function имя_функции (аргумент1, аргумент2, ...) As тип

команды

Return выражение ' или имя_функции = выражение

End Function

где аргумент1 и аргумент2 — переменные. Имена функций подчиняются тем же правилам, что и имена переменных. При вызове функции VB .NET выполняет команды, содержащиеся в определении функции. Значение, указанное после Return (или последнее значение, присвоенное имени функции), определяет результат вызова.

Хотя возвращаемое значение обычно используется в программе, VB также позволяет вызвать функцию простой командой вида foo(3) без присваивания.

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

Dim bar As Short = 3

Console.WriteLinedsBetweenlAnd10(bar))

VB .NET позволяет создавать функции с переменным числом аргументов. Дополнительная информация приведена далее в этой главе.

Процедуры

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

Option Strict On

Module Modulel

Sub ShowBottlesOfBeer(ByVal nbot As Integer)

Console.WriteLine(nbot & " bottles of beer on the wall")

Console.Writeline(nbot & " bottles of beer.")

Console.WriteLine("if one of those bottles hsould happen to fall")

Console.WriteLine(nbot -1&" bottles of beer on the wall")

End Sub

Sub Main()

Dim I As Integer

For I = 10 To 1 Step -1

ShowBottlesOfBeer(I)

Next

Console.WriteLine("All beer gone...")

Console. ReadLine()

End Sub

End Module

При вызове процедур указывать ключевое слово Sub не обязательно. Строку с вызовом процедуры из приведенного выше примера можно было записать и в таком виде:

Call ShowBottlesOfBeer(I)

Заголовок процедуры должен содержать объявления всех параметров с ключевыми словами ByVal или ByRef (по умолчанию используется ByVal, то есть передача по значению):

Sub имя_процедуры(В(ByVа1 аргумент1 As тип. ByVal аргумент2 As тип, ....)

команды

End Sub

При вызове процедуры в форме имя_процедуры(аргумент1, аргумент2, ...) или Call имя_процедуры(аргумент1. аргумент2, ...) VB .NET создает копии данных-аргументов и выполняет код, содержащийся в теле процедуры (поскольку в отличие от предыдущих версий по умолчанию параметры передаются по значению).

Преждевременный выход из функций или процедур

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

Function BallOut (X As Double) As Double If X < 0 Then

Return 0' Вернуть фиктивное значение Else

' Основные действия

End If

End Function

'Выход из процедур осуществляется командой

Exit Sub.

Передача массивов функциям и процедурам

В VB .NET, как и в прежних версиях VB, существуют удобные средства для работы с одномерными и многомерными массивами в процедурах и функциях. Впрочем, существуют некоторые нюансы, обусловленные передачей по ссылке и по значению; мы рассмотрим их в главе 4. Перебор содержимого массива осуществляется конструкцией For Each или (более распространенный вариант) стандартным циклом For с вычислением верхней границы при помощи функции UBound (). Ниже приведен пример функции поиска максимального элемента в массиве:

Function FindMax(ByVa1 a() As Integer

Dim finish As Integer = UBound(a)

Dim max As Integer = a(0)

Dim i As Integer

For i = 0 To finish

If a(i) > max Then max = a(i)

Next i

Return max End Function

Обобщенная форма вызова UBound(имя_массива, I) возвращает верхнюю границу по 1-му измерению массива. Для одномерных массивов (списков) параметр 1 является необязательным.

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

Процедуры и функции с необязательными аргументами

В VB. NET сохранена возможность определения процедур и функций с необязательными аргументами, но в отличие от VB6 для каждого необязательного параметра должно быть указано значение по умолчанию. Следующий пример демонстрирует синтаксис объявления необязательных параметров:

Sub ProcessAddress(TheName As String,

Address As String. City As String. State As String.

ZipCode As String. Optional ZipPlus4 As String = "0000")

В данном примере последний параметр является необязательным (Optional) и по умолчанию равен "0000".

В главе 4 описана перегрузка (overloading) —другой способ определения функций с необязательными параметрами.

VB .NET также позволяет определять процедуры и функции с произвольным количеством аргументов. Для этого в качестве параметра передается массив с ключевым словом РаramАrrау, как в следующем примере:

Function AddThemUp(ByVal ParamArray stuff() As Double) As Double

Dim total As Double = 0

Dim Number As Double = 0

Dim I As Integer

For I = 0 To UBound(stuff)

total = total + stuff(I)

Next

Return total End Function

Пример использования функции:

x = AddThemUp(3, 4. 5. 6)

В результате переменной х присваивается значение 18.

Именованные аргументы

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

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

Sub ProcessAddress(TheName As String.

Address As String. City As String. State As String,

ZipCode As String, Optional ZipPlus4 As String = "0000")

Вызов этой процедуры может выглядеть так:

ProcessAddress(Address := "The Whitehouse"

Name := "GeorgeW",

City := "DC". _

State:= String.Empty. _

ZipCode:= "12345")

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

Рекурсия

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

На концептуальном уровне рекурсивное решение выглядит следующим образом:

Решение задачи с применением рекурсии

If задача тривиальна

Решить Else

Упростить задачу, сводя ее к однотипной, но более простой задаче

Решить более простую задачу с применением рекурсии

End If

(Возможно) Объединить решение простой задачи (или задач)

с решением исходной задачи.

Рекурсивная функция или процедура постоянно вызывает сама себя, непрерывно упрощая задачу до тех пор, пока ее решение не станет тривиальным; в этот момент задача решается, и происходит возврат к предыдущему уровню. Применение рекурсии нередко связано с принципиальным изменением подхода к некоторым задачам, порождающим особенно элегантные решения и столь же элегантные программы (кстати, многие алгоритмы сортировки — такие, как встроенный метод Sort класса .NET Array, — основаны на принципе рекурсии).

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

  • НОД(4,6) = 2 (наибольшее число, на которое 4 и 6 делятся без остатка).
  • НОД(12,7) - 1 (числа 12 и 7 не делятся ни на одно целое число, большее 1).

    Около 2000 лет назад Евклид предложил следующий алгоритм вычисления НОД двух целых чисел а и b:

  • Если а делится на b, НОД= b. В противном случае НОД (а, b) = НОД (b, a Mod b)

Вспомним, что функция Mod возвращает остаток от целочисленного деления, а выражение a Mod b,равно 0 лишь в том случае, если а кратно b. Пример:

НОД(126.12)=НОД (12. 126 Mod 12)=НОД (12,6) - 6

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

Option Strict On Module Modulel

Function GCD(ByVal p As Long, ByVal q As Long) As Long

If Q Mod P = 0 Then

Return P Else

Return GCD(Q, P Mod Q)

End If

End Function Public Sub Main()

Console.WriteLine("The GCD of 36 and 99 is " & GCD(36. 99))

Console. ReadLine()

End Sub

End Module

Сначала обрабатывается тривиальный случай Q Mod P = 0. Если это условие не выполняется, функция GCD снова вызывает себя для более простого случая, поскольку в результате применения Mod мы переходим к меньшим числам. В приведенном примере объединять результаты не нужно (как, например, в функции сортировки).



Опубликовал admin
22 Авг, Воскресенье 2004г.



Программирование для чайников.