Я навчився трохи переглядати приховані особливості C # і був здивований, коли не зміг знайти щось подібне для VB.NET.
Отже, які є деякі його приховані чи менш відомі особливості?
Я навчився трохи переглядати приховані особливості C # і був здивований, коли не зміг знайти щось подібне для VB.NET.
Отже, які є деякі його приховані чи менш відомі особливості?
Відповіді:
Exception When
Положення в значній мірі невідомо.
Врахуйте це:
Public Sub Login(host as string, user as String, password as string, _
Optional bRetry as Boolean = False)
Try
ssh.Connect(host, user, password)
Catch ex as TimeoutException When Not bRetry
''//Try again, but only once.
Login(host, user, password, True)
Catch ex as TimeoutException
''//Log exception
End Try
End Sub
Enum
sОднією з реальних прихованих особливостей VB є completionlist
тег документації XML, який можна використовувати для створення власнихEnum
типів з розширеною функціональністю. Ця функція не працює в C #.
Один приклад з недавнього мого коду:
'
''' <completionlist cref="RuleTemplates"/>
Public Class Rule
Private ReadOnly m_Expression As String
Private ReadOnly m_Options As RegexOptions
Public Sub New(ByVal expression As String)
Me.New(expression, RegexOptions.None)
End Sub
Public Sub New(ByVal expression As String, ByVal options As RegexOptions)
m_Expression = expression
m_options = options
End Sub
Public ReadOnly Property Expression() As String
Get
Return m_Expression
End Get
End Property
Public ReadOnly Property Options() As RegexOptions
Get
Return m_Options
End Get
End Property
End Class
Public NotInheritable Class RuleTemplates
Public Shared ReadOnly Whitespace As New Rule("\s+")
Public Shared ReadOnly Identifier As New Rule("\w+")
Public Shared ReadOnly [String] As New Rule("""([^""]|"""")*""")
End Class
Тепер, призначаючи значення змінній, оголошеній як Rule
, IDE пропонує список можливих значень IntelliSense зRuleTemplates
.
Оскільки це функція, яка покладається на IDE, важко показати, як це виглядає, коли ви його використовуєте, але я просто використаю скріншот:
Список заповнень у дії http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
Насправді IntelliSense на 100% ідентичний тому, що ви отримуєте під час використання Enum
.
friend
або використовуючи той же клас, що і enum: Rule
замість RuleTemplate
.
Ви помітили оператора порівняння Like?
Dim b As Boolean = "file.txt" Like "*.txt"
Більше від MSDN
Dim testCheck As Boolean
' The following statement returns True (does "F" satisfy "F"?)'
testCheck = "F" Like "F"
' The following statement returns False for Option Compare Binary'
' and True for Option Compare Text (does "F" satisfy "f"?)'
testCheck = "F" Like "f"
' The following statement returns False (does "F" satisfy "FFF"?)'
testCheck = "F" Like "FFF"
' The following statement returns True (does "aBBBa" have an "a" at the'
' beginning, an "a" at the end, and any number of characters in '
' between?)'
testCheck = "aBBBa" Like "a*a"
' The following statement returns True (does "F" occur in the set of'
' characters from "A" through "Z"?)'
testCheck = "F" Like "[A-Z]"
' The following statement returns False (does "F" NOT occur in the '
' set of characters from "A" through "Z"?)'
testCheck = "F" Like "[!A-Z]"
' The following statement returns True (does "a2a" begin and end with'
' an "a" and have any single-digit number in between?)'
testCheck = "a2a" Like "a#a"
' The following statement returns True (does "aM5b" begin with an "a",'
' followed by any character from the set "L" through "P", followed'
' by any single-digit number, and end with any character NOT in'
' the character set "c" through "e"?)'
testCheck = "aM5b" Like "a[L-P]#[!c-e]"
' The following statement returns True (does "BAT123khg" begin with a'
' "B", followed by any single character, followed by a "T", and end'
' with zero or more characters of any type?)'
testCheck = "BAT123khg" Like "B?T*"
' The following statement returns False (does "CAT123khg" begin with'
' a "B", followed by any single character, followed by a "T", and'
' end with zero or more characters of any type?)'
testCheck = "CAT123khg" Like "B?T*"
VB знає примітивний вид typedef
через Import
псевдоніми:
Imports S = System.String
Dim x As S = "Hello"
Це корисніше при використанні спільно з загальними типами:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
вона повинна бути. ;-) Так чи інакше, ця помилка майже цілий рік не виявилась (і отримала 28 оновлень).
Imports Assert = xUnit.Assert
Ой! і не забувайте XML Literals .
Dim contact2 = _
<contact>
<name>Patrick Hines</name>
<%= From p In phoneNumbers2 _
Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
%>
</contact>
<string>This string contains "quotes" and it's OK.</string>.Value
(я знайшов це особливо зручно при написанні тестів на розборі CSV файлів , де кожне поле було в лапках було б. Чи не було весело , щоб уникнути всіх цих цитат вручну в моєму тестові лінії.)
Ініціалізація об’єктів теж є!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
- диво. На поверхні він працює аналогічно CType
оператору тим, що перетворює об’єкт з одного типу в інший. Однак це працює за набагато суворішим набором правил. CType
Тому фактична поведінка часто непрозора, і зовсім не видно, який вид конверсії здійснюється.
DirectCast
підтримує лише дві різні операції:
Будь-яка інша трансляція не працюватиме (наприклад, спроба розблокувати Integer
від a до a Double
) і призведе до помилки часу компіляції / часу виконання (залежно від ситуації та того, що може бути виявлено статичною перевіркою типу) Тому я використовуюDirectCast
коли це можливо, оскільки це найкраще фіксує мої наміри: залежно від ситуації я хочу розблокувати значення відомого типу або здійснити оновлення. Кінець історії.
Використання CType
, з іншого боку, залишає читача коду цікавитись, що дійсно планував програміст, оскільки він вирішує всі види різних операцій, включаючи виклик визначеного користувачем коду.
Чому це прихована особливість? Команда VB опублікувала керівництво 1, яке відмовляє від використання DirectCast
(хоча це насправді швидше!), Щоб зробити код більш рівномірним. Я стверджую, що це погана настанова, яку слід змінити: Коли це можливо, надайте перевагу DirectCast
більш загальному CType
оператору. Це робить код набагато зрозумілішим. CType
з іншого боку, слід викликати лише тоді, коли це дійсно призначено, тобто коли слід викликати CType
оператора звуження (пор. перевантаження оператора ).
1) Я не можу створити посилання на керівний принцип, але я виявив, що Пол Вік прийняв його (головний розробник команди VB):
У реальному світі ви навряд чи коли-небудь помітите різницю, тому ви можете також перейти з більш гнучкими операторами перетворення, такими як CType, CInt тощо.
(EDIT by Zack: Докладніше тут: Як я можу подати участь у VB.NET? )
TryCast
тоді, оскільки в основному мав кості відбирати під час поширеного використання CType
.
TryCast
працює лише на типи посилань, відповідно до документації.
If
умовний і злитий операторЯ не знаю, наскільки прихований ви б це назвали, але Iif ([вираз], [значення, якщо справжнє], [значення, якщо помилкове]) як функція "Об'єкт" може зараховуватися.
Це не так приховано, як застаріле ! VB 9 має If
оператора, який набагато краще і працює точно як умовний оператор C # і об'єднати його (залежно від того, що ви хочете):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Відредаговано, щоб показати інший приклад:
Це буде працювати з If()
, але викликати виняток ізIIf()
Dim x = If(b<>0,a/b,0)
:?
оператору C та Perl , це не просто спрощена версія.
Це приємне. Заява Select Case в VB.Net дуже потужна.
Звичайно, є стандарт
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Але є ще ...
Ви можете робити діапазони:
Select Case Amount
Case Is < 0
''//What!!
Case 0 To 15
Shipping = 2.0
Case 16 To 59
Shipping = 5.87
Case Is > 59
Shipping = 12.50
Case Else
Shipping = 9.99
End Select
І навіть більше ...
Ви можете (хоча це не є хорошою ідеєю) робити булеві перевірки кількох змінних:
Select Case True
Case a = b
''//Do X
Case a = c
''//Do Y
Case b = c
''//Do Z
Case Else
''//Exception case
End Select
Select Case True
тому, що він виглядає так, ніби він оцінює кожне з Case
тверджень і запускає код для кожного з них, що відповідає дійсності. Але насправді він оцінює їх один за одним і запускає код лише для першого, який є істинним. У If
цьому відношенні синтаксис значно чіткіший ( If...Else If...Else If...Else
).
Одним з основних застав, який я весь час використовую, є ключове слово With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
Мені просто не подобається набирати більше, ніж треба!
Найкращий і простий аналізатор CSV:
Microsoft.VisualBasic.FileIO.TextFieldParser
Додавши посилання на Microsoft.VisualBasic, це може бути використане будь-якою іншою мовою .Net, наприклад C #
(EDIT: Дізнайтеся більше тут: Чи слід завжди використовувати оператори AndAlso та OrElse? )
Статичні члени в методах.
Наприклад:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
У наведеній вище функції регулярний вираз шаблону буде створений лише один раз незалежно від того, скільки разів функція викликається.
Іншим використанням є збереження примірника "випадкових" навколо:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Крім того, це не те саме, що просто оголосити його як Спільного члена класу; елементи, оголошені таким чином, гарантовано також є безпечними для потоків. У цьому сценарії це не має значення, оскільки вираз ніколи не зміниться, але є й інші, де це може бути.
У vb є різниця між цими операторами:
/
це Double
\
буде Integer
ігноруючи інші
Sub Main()
Dim x = 9 / 5
Dim y = 9 \ 5
Console.WriteLine("item x of '{0}' equals to {1}", x.GetType.FullName, x)
Console.WriteLine("item y of '{0}' equals to {1}", y.GetType.FullName, y)
'Results:
'item x of 'System.Double' equals to 1.8
'item y of 'System.Int32' equals to 1
End Sub
Мені дуже подобається "Мій" Іменний простір, який був представлений у Visual Basic 2005. Мій це ярлик для декількох груп інформації та функціональності. Він забезпечує швидкий та інтуїтивний доступ до таких типів інформації:
Хоча рідко корисно, обробка подій може бути сильно налаштована:
Public Class ApplePie
Private ReadOnly m_BakedEvent As New List(Of EventHandler)()
Custom Event Baked As EventHandler
AddHandler(ByVal value As EventHandler)
Console.WriteLine("Adding a new subscriber: {0}", value.Method)
m_BakedEvent.Add(value)
End AddHandler
RemoveHandler(ByVal value As EventHandler)
Console.WriteLine("Removing subscriber: {0}", value.Method)
m_BakedEvent.Remove(value)
End RemoveHandler
RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("{0} is raising an event.", sender)
For Each ev In m_BakedEvent
ev.Invoke(sender, e)
Next
End RaiseEvent
End Event
Public Sub Bake()
''// 1. Add ingredients
''// 2. Stir
''// 3. Put into oven (heated, not pre-heated!)
''// 4. Bake
RaiseEvent Baked(Me, EventArgs.Empty)
''// 5. Digest
End Sub
End Class
Потім це можна перевірити наступним чином:
Module Module1
Public Sub Foo(ByVal sender As Object, ByVal e As EventArgs)
Console.WriteLine("Hmm, freshly baked apple pie.")
End Sub
Sub Main()
Dim pie As New ApplePie()
AddHandler pie.Baked, AddressOf Foo
pie.Bake()
RemoveHandler pie.Baked, AddressOf Foo
End Sub
End Module
Я щойно знайшов статтю, яка розповідає про "!" Оператор, також відомий як "оператор пошуку словника". Ось уривок зі статті за адресою: http://panopticoncentral.net/articles/902.aspx
Технічна назва для! Оператор - "оператор пошуку словника". Словник - це будь-який тип колекції, який індексується ключем, а не числом, подібно до того, як записи в англійському словнику індексуються словом, яке ви хочете визначити. Найпоширеніший приклад типу словника - System.Collections.Hashtable, який дозволяє додавати (ключ, значення) пар до хештету, а потім отримувати значення за допомогою клавіш. Наприклад, наступний код додає три записи до хештету, і шукає одну з них за допомогою клавіші "Pork".
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
The! Оператор може використовуватися для пошуку значень будь-якого типу словника, який індексує його значення за допомогою рядків. Ідентифікатор після! використовується як ключ в операції пошуку. Отже, вищенаведений код міг бути написаний:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
Другий приклад абсолютно рівнозначний першому, але просто виглядає набагато приємніше, принаймні, на мої очі. Я знаходжу, що є багато місць, де! Можна використовувати, особливо якщо мова йде про XML та Інтернет, де є лише тони колекцій, які індексуються рядком. Одне невдале обмеження - це те, що слідує за! як і раніше повинен бути дійсним ідентифікатором, тому якщо рядок, який ви хочете використовувати як ключ, містить у собі недійсний символ ідентифікатора, ви не можете використовувати! оператор. (Ви не можете, наприклад, сказати "Таблиця! AB $ CD = 5", оскільки $ не є законним в ідентифікаторах.) У VB6 і раніше ви можете використовувати дужки, щоб уникнути недійсних ідентифікаторів (тобто "Таблиця! [AB $ CD] "), але коли ми почали використовувати дужки, щоб уникнути ключових слів, ми втратили можливість це робити. В більшості випадків,
Щоб отримати дійсно технічне значення, x! Y працює, якщо x має властивість за замовчуванням, яка бере параметр String або Object. У цьому випадку x! Y змінюється на x.DefaultProperty ("y"). Цікавою стороною зауваження є те, що в лексичній граматиці мови є спеціальне правило, щоб все це працювало. The! символ також використовується як тип типу в мові, а символи типу з'їдаються перед операторами. Тож без спеціального правила x! Y буде відскановано як "x! Y" замість "x! Y". На щастя, оскільки в мові немає місця, де є два ідентифікатори підряд, ми просто ввели правило, що якщо наступний символ після! це початок ідентифікатора, ми вважаємо! бути оператором, а не типовим персонажем.
Це вбудований і певна перевага перед C #. Можливість реалізації методу інтерфейсу без використання однойменного імені.
Як от:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
Примушування ByVal
У VB, якщо ви загортаєте свої аргументи в додатковий набір дужок, ви можете перекрити декларацію ByRef методу і перетворити його в ByVal. Наприклад, наступний код виробляє 4, 5, 5 замість 4,5,6
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim R = 4
Trace.WriteLine(R)
Test(R)
Trace.WriteLine(R)
Test((R))
Trace.WriteLine(R)
End Sub
Private Sub Test(ByRef i As Integer)
i += 1
End Sub
Див. Аргумент, що не змінюється викликом процедури - базовою змінною
Передача параметрів за іменем і, таким чином, їх упорядкування
Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)
'Do stuff
End function
Використання:
Module Module1
Sub Main()
MyFunc() 'No params specified
End Sub
End Module
Також можна викликати, використовуючи специфікацію параметра ": =" у будь-якому порядку:
MyFunc(displayOrder:=10, msg:="mystring")
Оператор Use є новим, ніж VB 8, C # мав його з самого початку. Він закликає розпоряджатися автоматично для вас.
Напр
Using lockThis as New MyLocker(objToLock)
End Using
Псевдоніми імпорту також значною мірою невідомі:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Розглянемо наступну декларацію про подію
Public Event SomethingHappened As EventHandler
У C # ви можете перевірити наявність підписників на події, скориставшись таким синтаксисом:
if(SomethingHappened != null)
{
...
}
Однак компілятор VB.NET це не підтримує. Він фактично створює приховане поле приватного члена, яке не видно в IntelliSense:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Більше інформації:
http://jelle.druyts.net/2003/05/09/BehindTheScenesOfEventsInVBNET.aspx http://blogs.msdn.com/vbteam/archive/2009/09/25/testing-events-for-nothing-null-doug -rothaus.aspx
Якщо вам потрібна назва змінної, яка відповідає імені ключового слова, додайте його до дужок. Не належить. найкраща практика, хоча - але її можна використовувати розумно.
напр
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
наприклад, Приклад із коментарів (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Є кілька відповідей про XML Literals, але не про цей конкретний випадок:
Ви можете використовувати XML Literals, щоб укласти рядкові літерали, які в іншому випадку потрібно було б уникнути. Наприклад, рядкові літерали, які містять подвійні лапки.
Замість цього:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Ви можете зробити це:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Це особливо корисно, якщо ви тестуєте літерал для розбору CSV:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
( <string>
Звичайно, вам не потрібно використовувати тег; ви можете використовувати будь-який тег, який вам подобається.)
<q>
буде хорошим тегом, подібним до використання в Perl / Ruby. У всякому разі, це досить приємна ідіома. ПОДІБНО ДО!
DateTime можна ініціалізувати, обклавши дату номером #
Dim independanceDay As DateTime = #7/4/1776#
Ви також можете використовувати висновок типу разом із цим синтаксисом
Dim independanceDay = #7/4/1776#
Це набагато приємніше, ніж використовувати конструктор
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Ви можете мати 2 рядки коду лише в одному рядку. звідси:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Необов’язкові параметри
Додаткові можливості набагато простіше, ніж створення нових перевантажень, таких як:
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
Справа з заголовком у VB.Net може бути досягнута старим VB6 fxn:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Властивості з параметрами
Я займався деяким програмуванням на C # і виявив функцію, якої не було у VB.Net, але тут не згадували.
Приклад того, як це зробити (як і обмеження c #), можна побачити на: Використання типових властивостей get set у C # ... з параметрами
Я вийняв код з цієї відповіді:
Private Shared m_Dictionary As IDictionary(Of String, Object) = _
New Dictionary(Of String, Object)
Public Shared Property DictionaryElement(ByVal Key As String) As Object
Get
If m_Dictionary.ContainsKey(Key) Then
Return m_Dictionary(Key)
Else
Return [String].Empty
End If
End Get
Set(ByVal value As Object)
If m_Dictionary.ContainsKey(Key) Then
m_Dictionary(Key) = value
Else
m_Dictionary.Add(Key, value)
End If
End Set
End Property