Огляд Visual Basic 9.0, Різне, Програмування, статті

Зміст



Введення


Visual Basic завжди призначався для створення практичних бізнес-додатків, що працюють з даними. Якщо перехід на. NET надав розробникам переваги єдиної і керованої платформи, наступний випуск Visual Basic включає набір функцій, що значно впливають на продуктивність при створенні працюють з даними додатків. Ці розширення мови пропонують кошти запитів загального призначення, застосовні до всіх джерел даних: реляційних, графам ієрархічних об’єктів або XML-документами.


Дана стаття є оглядом цих нових функцій. Додаткові відомості, в тому числі оновлення мови і попередні версії компілятора Visual Basic, доступні в Visual Basic Developer Center (msdn.microsoft.com/vbasic/default.aspx).


Знайомство з Visual Basic 9.0


Щоб побачити переваги цих функцій мови на практиці, почнемо з реального прикладу – бази даних ЦРУ CIA World Factbook. У ній міститься різна географічна, економічна, соціальна та політична інформація про держави світу. У нашому прикладі почнемо зі схеми для назви держави та її столиці, загальною площею і чисельності населення. Ця схема представлена ​​на мові Visual Basic 9.0 за допомогою наступного класу (для стислості використовується псевдокод):






Class Country
Public Property Name As String
Public Property Area As Long
Public Property Population As Integer
End Class

Нижче представлений невеликий набір бази даних держави, який буде використаний в якості робочого прикладу:






Dim countries = {
New Country With { .Name = “Palau”, .Area = 458, .Population = 16952 }, _
New Country With { .Name = “Monaco”, .Area = 1.9, .Population = 31719 }, _
New Country With { .Name = “Belize”, .Area = 22960, .Population = 219296 }, _
New Country With { .Name = “Madagascar”, .Area = 587040, .Population =
13670507}}

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






Dim smallCountries = From country In countries _
Where country.Population < 1000000 _
Select country

For Each country In SmallCountries
Console.WriteLine(country.Name)
Next


Оскільки тільки в Мадагаскарі більше одного мільйона жителів, наведена вище скомпільована і виконана програма роздрукує наступний список назв держав:






Palau
Monaco
Belize

Давайте розглянемо програму докладніше, щоб зрозуміти функції Visual Basic 9.0, значно спростили її написання. Перш за все, в оголошенні виразів для країн Countries, використовується новий синтаксис об’єкта-ініціалізатор, New Country With {…,. Area = 458, …}. У ньому створюється екземпляр складного об’єкта за допомогою зрозумілого синтаксису, схожого з існуючим твердженням With, і з застосуванням вираження.


Оголошення також ілюструє використання неявно типізованих локальних змінних, В яких компілятор виводить тип локальної змінної Countries з виразу ініціалізатор з правого боку оголошення. Наведене вище оголошення є точним еквівалентом оголошення явно вираженою локальної змінної типу Country ():






Dim countries As Country() = {…}

Повторюємо, це все ще сильно типізовані оголошення; компілятор автоматично вивів тип з правої сторони локального оголошення, і програмісту не потрібно вводити цей тип в програму вручну.


Оголошення локальної змінної SmallCountries ініціалізується за допомогою виразу запиту в форматі SQL, в якому вибираються всі держави з населенням менше мільйона осіб. Схожість з SQL є навмисним, що дозволяє програмістам, вже знайомим з SQL, почати роботу з Visual Basic більш швидко:






Dim smallCountries = From country In Countries _
Where country.Population < 1000000 _
Select country

Зверніть увагу, що в цьому прикладі являє інше застосування явної типізації: компілятор виводить тип SmallCountries як IEnumerable (Of Country), виходячи їх типу результату виконуваного запиту. Компілятор перетворює сам вираз запиту у виклики інтерфейсу API з підтримкою LINQ, що реалізує оператори запитів для всіх типів, що реалізують IEnumerable (Of T). В цьому випадку результат перетворення простий:






Dim smallCountries As IEnumerable(Of Country) = _
Countries.Where(Function(country) country.Population < 1000000).
Select(Function(country) country)

У розширеному синтаксисі використовуються лямбда-функції, Вставлені безпосередньо в текст і повертають результат вираження. Лямбда-функція перетворюється в делегат і передається у функцію Where, яка визначається в бібліотеці операторів стандартних запитів як розширення інтерфейсу IEnumerable (Of T)


Ми розглянули деякі нові властивості Visual Basic 9.0, тепер приступимо до більш детального огляду.


Неявно типізовані локальні змінні


В оголошенні неявно типізованих локальних змінних їх тип виводиться з виразу-ініціалізатор в правій частині локального оголошення. Наприклад, компілятор виводить типи наступних змінних оголошень:






Dim population = 31719
Dim name = “Belize”
Dim area = 1.9
Dim country = New Country With .Name = “Palau”, …

Тому вони будуть точними еквівалентами наступних явно типізованих оголошень:






Dim population As Integer = 31719
Dim name As String = “Belize”
Dim area As Float = 1.9
Dim country As Country = New Country With { .Name = “Palau”, …}

Оскільки типи оголошень локальних змінних виводяться за допомогою нового режиму Option Infer On (включений за замовчуванням для нових проектів) незалежно від значення Option Strict, доступ до таких виразів завжди має ранню прив’язку. У Visual Basic 9.0 пізню прив’язку можна вказати явно, оголошуючи змінні типу Object, наприклад так:






Dim country As Object = New Country With  .Name = “Palau”, … }

Обчислення типів запобігає випадкове використання пізньої прив’язки і, що важливіше, дозволяє розширити прив’язку на нові типи даних, наприклад, на XML, що буде розглянуто нижче.


Мінлива управління циклом в утвердженні For … Next або For Each … Next також може бути неявно типізований змінної. При виборі змінної управління циклом, як в For I = 0 To SmallCountries.Count, або в For Each country In smallCountries, ідентифікатор створює нову неявно типізовану локальну змінну в межах циклу, тип якої виводиться з ініціалізатор чи висловлювання колекції. Застосовуючи цю можливість виведення типів, можна переписати цикл, що друкує малі країни:






For Each country In smallCountries
Console.WriteLine(country.Name)Next

Тип country виводиться з Country, типу елемента в SmallCountries.


Ініціалізатор об’єктів і масивів


У Visual Basic оператор With спрощує доступ до кількох членам складеного об’єкта, для чого не треба кожного разу писати ім’я об’єкта. Усередині оператора With вираз, що починається з точки, розцінюється як випадок, коли перед точкою стоїть ім’я цільового об’єкта оператора With. Наприклад, такі оператори ініціалізували новий примірник Country і послідовно ініціалізували поля наступних значень:






Dim palau As New Country()
With palau
.Name = “Palau”
.Area = 458
.Population = 16952
End With

Нові ініціалізатор об’єктів в Visual Basic 9.0 – це форми на основі With з використанням виразів. Вони спрощують створення примірників складних об’єктів. С з допомогою можна звести два наведених вище оператора до одного (неявно типизированном) локальному оголошенню:






Dim palau = New Country With { _
.Name = “Palau”, _
.Area = 458, _
.Population = 16952 _
}

Можливість використовувати вираз для ініціалізації об’єкта важлива для запитів. Зазвичай запит виглядає як оголошення об’єкта, ініціалізований виразом Select праворуч від знака рівності. Оскільки умова Select повертає вираз, слід мати можливість ініціалізувати цілий об’єкт одним виразом.


Як ми бачимо, ініціалізатор об’єктів також придатні для створення наборів складних об’єктів. Можна ініціалізувати масиви і вивести типи елементів за допомогою виразу ініціалізатор масиву. Наприклад, якщо міста оголошені як класи,






Class City
Public Property Name As String
Public Property Country As String
Public Property Longitude As Long
Public Property Latitude As Long
End Class

ми в нашому прикладі країн можемо створити масив столиць:






Dim Capitals = { _
New City With { _
.Name = “Antanarivo”, _
.Country = “Madagascar”, _
.Longitude = 47.4, _
.Latitude = -18.6 }, _
New City With { _
.Name = “Belmopan”, _
.Country = “Belize”, _
.Longitude = -88.5, _
.Latitude = 17.1 }, _
New City With { _
.Name = “Monaco”, _
.Country = “Monaco”, _
.Longitude = 7.2, _
.Latitude = 43.7 }, _
New City With { _
.Country = “Palau”,
.Name = “Koror”, _
.Longitude = 135, _
.Latitude = 8 } _
}

Анонімні типи


Часто потрібно видалити або пропустити в результатах запиту деякі члени типу. Наприклад, нам можемо знадобитися дізнатися Name і Country для всіх тропічних столиць. Щоб з’ясувати, чи є вони тропічними, використовуємо стовпці вихідних даних Latitude і Longitude (широта і довгота), але в кінцевому результаті ця цифра ні до чого. У Visual Basic 9.0 для цього ми створюємо новий екземпляр об’єкта (без іменування типу) для кожної столиці, широта якої потрапляє в діапазон між північним тропіком (Рака) і південним (Козерога):






Const TropicOfCancer = 23.5
Const TropicOfCapricorn = -23.5
Dim tropical = From city In Capitals _
Where TropicOfCancer <= city.Latitude _
AndAlso city.Latitude >= TropicOfCapricorn _
Select New With city.Name, city.Country

Виведений тип локальної змінної tropical – набір екземплярів анонімного типу, а саме (використовуючи псевдо-код) IEnumerable (Of {Name As String, Country As String}). Компілятор Visual Basic створить неявно описаний клас, наприклад, _Name_As_String_Country_As_String_, назви і тип членів якого виводяться з ініціалізатор об’єкту:






Class _Name_As_String_Country_As_String_
Public Property Name As String
Public Property Country As String

End Class

Всередині однієї програми компілятор об’єднає ідентичні анонімні типи. Два ініціалізатор анонімних об’єктів, у яких зазначене однакова послідовність властивостей імен і типів в тому ж порядку, будуть створювати екземпляри одного і того ж анонімного типу. Анонімні типи в Visual Basic створюються на основі Object, який дозволяє компілятору передавати їх як аргументи і результати функцій.


Оскільки анонімні типи зазвичай використовуються для відбору існуючих типів, Visual Basic 9.0 дозволяє використовувати синтаксис New With {city.Name, city.Country} як спрощення для New With {. Name = city.Name, . Country = city.Country}. При використанні такої нотації в складі запиту її можна зробити ще коротше:






Dim Tropical = From city In Capitals _
Where TropicOfCancer <= city.Latitude _
AndAlso city.Latitude >= TropicOfCapricorn _
Select city.Name, city.Country

Обидві ці скорочені форми ідентичні повною формою, наведеною вище.


Глибока підтримка XML


LINQ to XML – Новий API-інтерфейс для обробки XML в пам’яті, спеціально створений для втілення новітніх можливостей. NET Framework, таких, як Language-Integrated Query framework. Подібно до того як розширення в обробці запитів дають простий і зручний синтаксис в порівнянні з базовими можливостями. NET Framework, в Visual Basic 9.0 додана глибока підтримка LINQ to XML, за допомогою XML-літералів і XML-властивостей.


Щоб проілюструвати роботу з XML-літералами, побудуємо запит до плоских реляційних джерел даних Countries і Capitals, і створимо ієрархічну XML-структуру, в якій столиця кожної країни буде зберігатися як дочірній елемент і розрахунок щільності населення як атрибут.


Щоб знайти столицю цієї країни, ми виконуємо з’єднання імені-члена кожної країни з країною-членом кожного міста. Отримавши країну та її столицю, ми легко можемо сформувати XML-фрагмент, написавши вираз для підстановки. Для вираження Visual Basic підстановка пишеться в синтаксисі, що нагадує ASP: Name = <% = country.Name%> або <% = city.Name%> . Ось це запит, що поєднує XML-літерали і роботу з даними:






Dim countriesWithCapital As XElement = _
<Countries>
<%= From country In Countries, city In Capitals _
Where country.Name = city.Country _
Select <Country Name=<%= country.Name %>
Density=<%= country.Population / country.Area %>>
<Capital>
<Name><%= city.Name %></Name>
<Longitude><%= city.Longitude %></Longitude>
<Latitude><%= city.Latitude %></Latitude>
</Capital>
</Country> _
%>
</Countries>

Тип XElement можна опустити з опису, в цьому випадку він буде виводитися, як це відбувається для будь-якого локального оголошення.


У цьому оголошенні результат запиту Select заміщає структуру всередині елемента . Запит Select – це обчислюване вираз першого рівня і він позначений звичними для стилю ASP тегами <% = і%> в . Оскільки результатом виконання запиту Select буде вираз, і XML-літерали – теж вирази, всередині Select допустимо. таким чином, цей вкладений літерал сам містить вкладені вирази для атрибутів для назв і координат століцCountry.Name, і Country.Population / Country.Area.


При компіляції та запуску наведений запит повертає наступний XML-документ (злегка змінений у порівнянні з форматуванням в IDE для економії місця):






<Countries>
<Country Name=”Palau” Density=”0.037117903930131008″>
<Capital>
<Name>Koror</Name><Longitude>135</Longitude><Latitude>8</Latitude>
</Capital>
</Country>
<Country Name=”Monaco” Density=”16694.21052631579″>
<Capital>
<Name>Monaco</Name><Longitude>7.2</Longitude><Latitude>3.7</Latitude>
</Capital>
</Country>
<Country Name=”Belize” Density=”9.5512195121951216″>
<Capital>
<Name>Belmopan</Name><Longitude>-88.5</Longitude><Latitude>17.1</Latitude>
</Capital>
</Country>
<Country Name=”Madagascar” Density=”23.287181452711909″>
<Capital>
<Name>Antananarivo</Name>
<Longitude>47.4</Longitude><Latitude>-18.6</Latitude>
</Capital>
</Country>
</Countries>

Visual Basic 9.0 компілює XML-літерали в звичайні об’єкти System.Xml.Linq, забезпечуючи повну сумісність між Basic та іншими мовами, що використовують LINQ to XML. У цьому прикладі код, створений компілятором (Якщо його можна було б побачити), буде наступним:






Dim countriesWithCapital As XElement = _
New XElement(“Countries”, _
From country In Countries, city In Capitals _
Where country.Name = city.Country _
Select New XElement(“Country”, _
New XAttribute(“Name”, country.Name), _
New XAttribute(“Density”, country.Population/country.Area), _
New XElement(“Capital”, _
New XElement(“Name”, city.Name), _
New XElement(“Longitude”, city.Longitude), _
New XElement(“Latitude”, city.Latitude))))

Крім створення XML, Visual Basic 9.0 також спрощує доступ до XML-структурам через XML-властивості; це означає, що в період виконання ідентифікатори коду Visual Basic прив’язуються до відповідних атрибутів і елементам. Наприклад, щільність населення всіх країн приклад можна надрукувати наступним способом:



Якщо ці можливості поєднати разом, код різко скоротиться і спроститься:






For Each country In countriesWithCapital.<Country>
Console.WriteLine(“Density = ” & country.@Density)
Console.WriteLine(“Latitude = ” & country…<Latitude>.Value)
Next

Компілятору відомо, що можна використовувати пізню прив’язку до звичайних об’єктів, якщо в оголошенні, привласненні або ініціалізації цільове вираз має тип Object, а не більш специфічний тип. Точно так же компілятору відомо, що слід використовувати прив’язку поверх XML, якщо цільове вираз – тип або набір XElement, XDocument, або XAttribute.


Як результат пізнього прив’язування поверх XML, компілятор транслює це все таким чином:



Покращення запитів


Оператори запиту – Це оператори Select, Order By або Where, що працюють зі значеннями по всьому набору даних. Вираз запиту – Це серія операторів запитів, які мають справу з конкретним набором. Наприклад, такий вираз запиту читає набір країн і повертає назви всіх країн з населенням менше мільйона осіб:






Dim smallCountries = From country In Countries _
Where country.Population < 1000000 _
Select country

Синтаксис вираження запиту наближений до стандартного реляційному синтаксису мови SQL, тому будь-який знайомий з ним здатний створювати такі вирази після мінімального навчання. У той же час синтаксис не обмежений SQL, і не всі вирази запиту є трансляцією з SQL в Visual Basic. Оскільки SQL розроблявся виходячи з чисто реляційної моделі, деякі з його концепцій не працюють в системі типів, в основі якої лежить ієрархія. Крім того, деякі елементи синтаксису і семантики SQL конфліктують або не взаємодіють з існуючою семантикою і синтаксисом Visual Basic. Таким чином, хоча вираження запиту повинні бути знайомі всім, хто знає SQL, необхідно вивчити і їх відмінності.


Вирази запиту транслюються у виклики до базових операторам вибірки даних для типів, до яких можливий запит, і які зазначені як вихідні типи в умові From. Оскільки оператори вибірки даних зазвичай визначаються для вихідних типів як методи розширення, ці типи можна пов’язати з будь-якими наявними в системі операторами. З цього випливає, що при імпорті тієї чи іншої конкретної реалізації синтаксис виразів запиту знову може бути прив’язаний до різних API-інтерфейсів LINQ. Таким шляхом висловлення запиту можуть знову бути прив’язані до реалізацій LINQ до SQL або LINQ до об’єктів (локальний модуль обробки запитів, що виконує їх в пам’яті).


В деяких операторах запитів, таких як From, Select і Group By, вводяться спеціальні види локальних змінних, звані range variables – змінними діапазону. За замовчуванням область дії такої змінної простягається від оператора, де вона введена, до оператора, який її приховує, вона представляє властивість або стовпець окремого рядка в колекції при обчисленні запиту. Наприклад, в наступному запиті:






Dim smallCountries = From country In Countries _
Where country.Population < 1000000 _
Select country

в операторі From вводиться мінлива діапазону country типу «Country». У наступному операторі запиту Where вона використана, щоб позначити кожну індивідуальну запис в умові country.Population < 1000000.


В деяких операторах запиту, наприклад, Distinct, змінні управління не використовуються або не міняються. В інших операторів, таких як Select, припиняє дію поточних змінних діапазону і вводять нові змінні діапазону. Наприклад, в запиті:






Dim smallCountries = From country In Countries _
Select country.Name, Pop = country.Population
Order By Pop

Оператор запиту Order By має доступ тільки до змінних Name і Pop, введеним оператором Select; якщо оператор Order By спробує послатися на country, при компіляції виникне помилка.


Якщо запит завершується без оператора Select, тип отриманого елемента колекції буде таким, як якщо б у вибірці Select були присутні всі змінні управління з цієї області видимості:






Dim countriesWithCapital = From country In Countries, city In Capitals _
Where country.Name = city.Country

Підсумковий тип в цьому визначенні буде (в псевдо-коді, щоб показати анонімний тип) IEnumerable (Of {Country As Country, City As City}).


Чим вираження запиту відрізняються від SQL: гнучкість і ієрархічні дані


Структура виразів запиту в Visual Basic 9.0 є надзвичайно гнучкою. Вдосконалені оператори можна довільно додавати і вкладати один в одного. Це спрощує розуміння великого запиту, так як можна аналізувати його окремі подвираженія, а також відстеження типів. У той же час такий принцип відрізняється від запитів в SQL, де вони аналізуються як єдиний блок.


Крім того, в API-інтерфейси з підтримкою LINQ прагнуть використовувати оператори з відкладеним (deferred) виконанням. Відкладене виконання означає, що запит не буде оброблятися, поки не буде звернення до результатів. Для LINQ to SQL це означає, що запит не буде переданий в SQL, поки не будуть затребувані результати. Це означає, що поділ запитів на окремі оператори не означає багаторазового запиту до бази. В результаті те, що в SQL зазвичай є вкладеним запитом, в LINQ стає гнучким запитом.


Одна з причин, чому в SQL відсутній структурна гнучкість – основна реляційна модель даних сама по собі слабо структурована. Наприклад, таблиці не можуть містити підтаблиці, іншими словами, все таблиці повинні бути плоскими. В результаті замість дроблення складних виразів на більш дрібні одиниці програмісти SQL пишуть монолітні вираження, результатом яких є плоскі таблиці, відповідні моделі даних SQL. Оскільки Visual Basic заснований на системі типів CLR, не існує обмежень, які типи можуть виступати як компоненти інших типів. Крім статичних правил типізації, не існує обмежень на тип виразів, які виступають компонентами інших виразів. В результаті не тільки рядки, об’єкти і XML-структури, а й Active Directory, файли, елементи реєстру тощо – повноправні представники як джерел, так і результатів запиту.


Оператори запиту


Ті, хто добре знайомий з SQL, дізнаються в основних операторах. NET, що працюють з наборами даних, операції реляційної алгебри. У їх числі – проекція, вибірка, логічне перетин, угруповання й сортування і вони відповідають моделі в обробнику запитів.



Повний синтаксис всіх операторів можна знайти в описі мови, але для ілюстрації наведемо наступний приклад. У ньому знаходяться столиці кожної держави і назви країн розставляються по широті розташування столиці:






Dim countriesWithCapital = _
From country In Countries _
Join city In Capitals On country.Name Equals city.Country _
Order By city.Latitude _
Select country.Name

Для запитів, обчислює скалярний значення на підставі колекції, використовується оператор Aggregate. У наступному запиті в одному операторі визначається кількість малих країн і підраховує щільність їх населення:






Dim popInfo = _
Aggregate country In Countries _
Where country.Population < 1000000 _
Into Total = Count(), Density = Average(country.Population/country.Area)

Функції найбільш часто з’являються в поєднанні з розбивкою вихідної колекції. Наприклад, можна згрупувати всі країни на підставі критерію, чи є вони тропічними, і потім порахувати їх в кожній групі. Для цього ці оператори можна використовувати в поєднанні з умовами Group By і Group Join. У наведеному нижче прикладі допоміжна функція IsTropical перевіряє, чи є клімат в City тропічним:






Function IsTropical() As Boolean
Return TropicOfCancer =< Me.Latitude AndAlso Me.Latitude >= TropicOfCapricorn
End Function

Маючи таку функцію, виконаємо ту ж вибірку, як і вище, але спочатку поділимо колекцію пар Country і Capital на групи, для яких Country.IsTropical буде однаковим. У цьому випадку буде дві таких групи: в одну потрапляють тропічні країни Палау, Беліз і Мадагаскар; в іншу – нетропічних Монако.


























Табл. 1. Параметри об’єкта CustomTaskPane
Умова Країна Столиця
Country.IsTropical() = True
 
Palau
 
Koror
 
 
 
Belize
 
Belmopan
 
 
 
Madagascar
 
Antanarivo
 
Country.IsTropical() = False
 
Monaco
 
Monaco
 

Потім порахуємо чисельність населення і середню щільність. Результат буде колекцією пар Total As Integer і Density As Double:






Dim countriesByClimate = _
From country In Countries _
Join city In Capitals On country.Name Equals city.Country _
Group By country.IsTropical()
Into Total = Count(), Density = Average(country.Population/country.Area)

Попередній запит приховує достатню складність. Запит нижче видає той же результат за допомогою лямбда-виразів і методів розширення (method-call syntax):






Dim countriesByClimate7 = _  countries. _
SelectMany( _
Function(country) Capitals, _
Function(country, city) New With {country, city}). _
Where(Function(it) it.country.Name = it.city.Country). _
GroupBy( _
Function(it) it.city.IsTropical(), _
Function(IsTropical, Group) _
New With { _
IsTropical, _
.Total = Group.Count(), _
.Density = Group.Average( _
Function(it) it.country.Population / it.country.Area _
) _
} _
)

Методи розширення та лямбда-виразу


Міць інфраструктури запитів в. NET Framework багато в чому забезпечується за рахунок методів розширення і лямбда-виразів. Методи розширення – загальнодоступні і забезпечені спеціальними атрибутами, що дозволяє запускати їх як методи примірників. Більшість методів розширення мають однакові формати дзвінка. Перший аргумент – Примірник об’єкта, з яким працює метод, другий – вираз. Наприклад, метод Where, в який транслюється умова Where, має наступний формат виклику:






Module IEnumerableExtensions
<Extension> _
Function Where (Of TSource) _
(Source As IEnumerable(Of TSource), _
predicate As Func(Of TSource, Boolean)) As IEnumerable(Of TSource)

End Function
End Module

Так як багато стандартні оператори запиту, такі, як Where, Select, SelectMany і так далі, визначаються як методи розширення, в які передаються делегати виду Func (Of S, T), компілятор відходить від вимоги створювати делегати для предикатів. Замість цього делегати, які захоплюють навколишній контекст, і передають їх в викликається метод. Наприклад, за допомогою наступного запиту компілятор створює лямбда-виразу, що є делегатами для передачі у функції Select і Where:






Dim smallCountries = From country In countries _
Where country.Population < 1000000 _
Select country.Name

Компілятор створює два лямбда-виразу для джерела інформації і предиката відповідно:






Function(Country As Country) country.Name
Function (Country As Country) country.Population < 1000000

І попередній запит транслюється у виклики методів до стандартної інфраструктурі запитів, а джерело і лямбда-вираз передаються як аргументи:






Dim smallCountries = _
Enumerable.Select( _
Enumerable.Where(countries, _
Function (country As Country) country.Population < 1000000), _
Function(country As Country) country.Name)

Типи, що приймають значення NUll


В реляційних базах даних є спеціальна семантика для значень “null”, яка часто несумісна зі звичайними мовами програмування і незнайома програмістам. У додатках, що працюють з даними, життєво необхідно грамотно і точно звертатися з цією семантикою. В. NET Frameworks 2.0 CLR додана підтримка null-значень за допомогою узагальненого типу Nullable (Of T As Structure). З його допомогою можна оголосити null-версії для розмірних типів Integer, Boolean, Date і так далі. З причин, які скоро будуть зрозумілими, синтаксис Visual Basic для Обнуляємо типів наступний: T?.


Наприклад, можна додати новий член до класу Country, в якому буде записана дату отримання країною незалежності:






Partial Class Country
Public Property Independence As Date?
End Class

Але не всі країни є суверенними. Дата отримання незалежності Палау # 10/1/1994 #, а Брітансіке Віргінські острови – територія, залежна від Сполученого Королівства, і тому в якості дати незалежності потрібно написати Nothing.






Dim palau = _
New Country With { _
.Name = “Palau”, _
.Area = 458, _
.Population = 16952, _
.Independence = #10/1/1994# }

Dim virginIslands = _
New Country With { _
.Name = “Virgin Islands”, _
.Area = 150, _
.Population = 13195, _
.Independence = Nothing }


Visual Basic 9.0 буде підтримувати трійкову логіку і null-арифметику при обробці null-величин. Це означає, що якщо один з операндів арифметичній, порівняльної, логічної або побітової операції, зсуву, рядки або типу має тип Nothing, результатом теж буде Nothing. Якщо обидва операнда мають деяке значення, операція виконується для основних типів операндів і результат перетворюється назад в null-тип.


Оскільки і Palau.Independence і VirginIslands.Independence мають тип Date?, Компілятор буде використовувати null-арифметику для наведених нижче вирахувань, і тому котрого тип логічних змінних PLength і VILength буде TimeSpan?.






Dim pLength = #8/24/2005# – Palau.Independence          ‘ 3980.00:00:00

Значення PLength одно 3980.00:00:00, так як жоден з операндів не дорівнює Nothing. З іншого боку, оскільки значення VirginIslands.Independence одно Nothing, результат знову буде типу TimeSpan?, але значення VILength буде Nothing через правил обробки null:






Dim vILength = #8/24/2005# – virginIslands.Independence ‘ Nothing

Так само, як в SQL, оператори порівняння обробляють значення типу null, і в логічних операторах будует використовуватися трійкова логіка. У твердженнях If і While значення Nothing буде інтерпретуватися як False; отже, в наступному прикладі коду буде обрана гілку Else:






If vILength < TimeSpan.FromDays(10000)  …
Else

End if

Врахуйте, що для трійкової логіки результатом перевірки рівностей X = Nothing і Nothing = X завжди буде Nothing; для перевірки, чи є X Nothing, ми повинні використовувати логічне порівняння X Is Nothing або Nothing Is X.


Несуворі делегати


При створенні делегатів з допомогою AddressOf або Handles в Visual Basic 8.0, методи, які з ними працюють, повинні мати таку ж сигнатуру, що й тип, для якого створюється делегат. У наведеному нижче прикладі сигнатура підпрограми OnClick повинна точно відповідати сигнатурі делегата обробки події Delegate Sub EventHandler (sender As Object, e As EventArgs), який оголошується в типі Button:






Dim WithEvents btn As New Button()Sub OnClick(sender As Object, e As EventArgs)
Handles B.Click MessageBox.Show(“Hello World from” & btn.Text)End Sub

У той же час при виклику функцій і підпрограм, які не є делегатами, Visual Basic не вимагає точної відповідності фактичних аргументів одному з методів, який ми намагаємося викликати. Як показано в наступному прикладі, можна викликати підпрограму OnClick з фактичними аргументами типу Button і типу MouseEventArgs, які є, відповідно, похідними від Object і EventArgs:






Dim m As New MouseEventArgs(MouseButtons.Left, 2, 47, 11,0)OnClick(btn, m)

І навпаки, припустимо, ми визначаємо підпрограму RelaxedOnClick, в яку передаються два параметри Object, і потім ми можемо викликати її з фактичними аргументами типу Object і EventArgs:






Sub RelaxedOnClick(sender As Object, e As Object) Handles btn.Click
MessageBox.Show(“Hello World from” & btn.Text))
End Sub
Dim e As EventArgs = m
Dim s As Object = btn
RelaxedOnClick(btn,e)

У Visual Basic 9.0 прив’язка до делегатів ослаблена, щоб відповідати викликам методів. Це означає, що якщо можливо викликати функцію або підпрограму з фактичними аргументами, які точно відповідають формальним параметрам і повертається типам делегата, такий виклик допустимо. Іншими словами, прив’язка та визначення делегатів буде підкорятися тій же логіці перевантаження і приведення типів, що і виклики цього методів.


З цього випливає, що в Visual Basic 9.0 ми можемо прив’язати підпрограму RelaxedOnClick, в яку передаються два параметри Object, до події Click об’єкта Button:






Sub RelaxedOnClick(sender As Object, e As Object) Handles btn.Click
MessageBox.Show((“Hello World from” & btn.Text)
End Sub

В обробниках подій рідко використовуються обидва аргументи sender і EventArgs. Зазвичай обробник отримує доступ до стану елемента управління, якому належить подія, і ігнорує ці два аргументи. Для підтримки цієї звичайної ситуації, правила для делегатів можна послабити настільки, що не передавати в них аргументи взагалі, якщо при цьому не виникає невизначеність. Іншими словами, можна просто написати таке:






Sub RelaxedOnClick Handles btn.Click
MessageBox.Show(“Hello World from” & btn.Text)
End Sub

Зрозуміло, що спрощення делегатів також застосовується при створенні делегатів, які використовують AddressOf або вирази, навіть якщо група методів є викликами з пізньою прив’язкою:






Dim F As EventHandler = AddressOf RelaxedOnClick
Dim G As New EventHandler(AddressOf btn.Click)

Висновок


Visual Basic 9.0 уніфікує доступ до даних незалежно від їхнього джерела: до реляційних баз даних, XML-документами, або довільним графам об’єктів, постійно присутніх або зберігаються в пам’яті. Уніфікація зачіпає стилі, прийоми, засоби та моделі програмування. Особливо гнучкий синтаксис Visual Basic спрощує додавання до мови розширень, таких, як XML-літерали і SQL-подібні вирази запитів. За рахунок того, що чужий синтаксис переноситься з строкових констант в мову Visual Basic, вдається значно скоротити пряму роботу з новими API-інтерфейсами. NET при запитах, спростити роботу за рахунок використання IntelliSense і смарт-тегів, і значно поліпшити налагодження і перевірку при компіляції.


Такі можливості, як обчислення типів, ініціалізатор об’єктів і несуворі делегати, різко знижують надмірність коду, і кількість винятків із правил, які необхідно вивчити і пам’ятати програмістам, не знижуючи при цьому продуктивність додатків.


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


Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*