Sporo się nauczyłem przeglądając ukryte funkcje języka C # i byłem zaskoczony, gdy nie mogłem znaleźć czegoś podobnego dla VB.NET.
Jakie są więc niektóre z jego ukrytych lub mniej znanych funkcji?
Sporo się nauczyłem przeglądając ukryte funkcje języka C # i byłem zaskoczony, gdy nie mogłem znaleźć czegoś podobnego dla VB.NET.
Jakie są więc niektóre z jego ukrytych lub mniej znanych funkcji?
Odpowiedzi:
Exception When
Klauzula jest w dużej mierze nieznane.
Rozważ to:
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
sJedną z prawdziwych ukrytych funkcji VB jest completionlist
znacznik dokumentacji XML, którego można użyć do tworzenia własnych Enum
typów o rozszerzonej funkcjonalności. Ta funkcja nie działa jednak w języku C #.
Jeden przykład z mojego niedawnego kodu:
'
''' <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
Teraz podczas przypisywania wartości do zmiennej zadeklarowanej jako Rule
środowisko IDE oferuje listę IntelliSense z możliwymi wartościami z RuleTemplates
.
Ponieważ jest to funkcja, która opiera się na IDE, trudno jest pokazać, jak to wygląda, gdy jej używasz, ale użyję tylko zrzutu ekranu:
Lista ukończenia w akcji http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
W rzeczywistości IntelliSense jest w 100% identyczny z tym, co otrzymujesz podczas korzystania z Enum
.
friend
lub używając tej samej klasy co enum: Rule
zamiast RuleTemplate
.
Czy zauważyłeś operator porównania Like?
Dim b As Boolean = "file.txt" Like "*.txt"
Więcej z 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 zna prymitywny rodzaj aliasów typedef
via Import
:
Imports S = System.String
Dim x As S = "Hello"
Jest to bardziej przydatne w połączeniu z typami ogólnymi:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
powinno być. ;-) Jakoś ten błąd pozostał niewykryty (i zebrał 28 głosów pozytywnych) przez prawie cały rok.
Imports Assert = xUnit.Assert
O! i nie zapomnij o literałach XML .
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
(Znalazłem to szczególnie przydatne przy pisaniu testów na parsowanie plików CSV, gdzie każdy polu została w cudzysłowie Byłoby. Nie były zabawy na ucieczkę te wszystkie cytaty ręcznie w moim linie testowe)
Inicjalizacja obiektu też jest tam!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
jest cudem. Na powierzchni działa podobnie do CType
operatora, ponieważ konwertuje obiekt z jednego typu na inny. Jednak działa na znacznie bardziej rygorystycznych zasadach. CType
W związku z tym rzeczywiste zachowanie jest często nieprzejrzyste i nie jest wcale jasne, jaki rodzaj konwersji jest wykonywany.
DirectCast
obsługuje tylko dwie różne operacje:
Każde inne rzutowanie nie zadziała (np. Próba rozpakowania Integer
do a Double
) i spowoduje błąd kompilacji / czasu wykonania (w zależności od sytuacji i tego, co można wykryć przez statyczne sprawdzanie typu). Dlatego używam, DirectCast
gdy tylko jest to możliwe, ponieważ najlepiej oddaje to mój zamiar: w zależności od sytuacji chcę albo rozpakować wartość znanego typu, albo wykonać upcast. Koniec opowieści.
CType
Z drugiej strony, użycie pozostawia czytelnika z pytaniem o to, co tak naprawdę zamierzał programista, ponieważ rozwiązuje to wszelkiego rodzaju różne operacje, w tym wywoływanie kodu zdefiniowanego przez użytkownika.
Dlaczego jest to ukryta funkcja? Zespół VB opublikował wytyczną 1, która zniechęca do używania DirectCast
(mimo że jest w rzeczywistości szybszy!) W celu ujednolicenia kodu. Twierdzę, że jest to zła wskazówka, którą należy odwrócić: jeśli to możliwe, faworyzuj DirectCast
bardziej ogólny CType
operator. Dzięki temu kod jest znacznie bardziej przejrzysty. CType
z drugiej strony, powinno być wywoływane tylko wtedy, gdy jest to rzeczywiście zamierzone, tj. gdy należy wywołać CType
operator zawężający (por. przeciążanie operatorów ).
1) Nie mogę znaleźć linku do wytycznych, ale znalazłem podejście Paula Vicka (głównego programisty zespołu VB):
W prawdziwym świecie prawie nigdy nie zauważysz różnicy, więc równie dobrze możesz wybrać bardziej elastyczne operatory konwersji, takie jak CType, CInt itp.
(EDIT by Zack: Dowiedz się więcej tutaj: Jak przesyłać w VB.NET? )
TryCast
ponieważ miałem głównie kość do skubania przy powszechnym użyciu CType
.
TryCast
działają tylko na typach referencyjnych, zgodnie z dokumentacją.
If
operator warunkowy i koalescencyjnyNie wiem, jak można by to nazwać ukrytym, ale funkcja Iif ([wyrażenie], [wartość, jeśli prawda], [wartość, jeśli fałsz]) może liczyć funkcję As Object.
Jest nie tyle ukryty, co przestarzały ! VB 9 ma If
operator, który jest znacznie lepszy i działa dokładnie tak, jak operator warunkowy i koalescencyjny C # (w zależności od tego, co chcesz):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Edytowano, aby pokazać inny przykład:
To zadziała If()
, ale spowoduje wyjątek w przypadkuIIf()
Dim x = If(b<>0,a/b,0)
:?
operatora C i Perla , nie jest to tylko uproszczona wersja.
To jest fajne. Instrukcja Select Case w VB.Net ma bardzo duże możliwości.
Jasne, że jest standard
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Ale jest więcej ...
Możesz robić zakresy:
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
I nawet więcej...
Możesz (chociaż może to nie być dobry pomysł) sprawdzać wartości logiczne wielu zmiennych:
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
jest to, że wygląda tak, jakby ocenia każdy z Case
wypowiedzi i uruchamia kod dla każdego z nich, który jest prawdziwy. Ale w rzeczywistości ocenia je pojedynczo i uruchamia kod tylko dla pierwszego, który jest prawdziwy. Pod tym względem składnia for If
jest znacznie jaśniejsza ( If...Else If...Else If...Else
).
Jednym z głównych sposobów oszczędzania czasu, których używam cały czas, jest słowo kluczowe With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
Po prostu nie lubię pisać więcej niż muszę!
Najlepszy i łatwy parser CSV:
Microsoft.VisualBasic.FileIO.TextFieldParser
Dodając odniesienie do Microsoft.VisualBasic, można to wykorzystać w dowolnym innym języku .Net, np. C #
(EDYCJA: Dowiedz się więcej tutaj: Czy zawsze powinienem używać operatorów AndAlso i OrElse? )
Statyczne składowe w metodach.
Na przykład:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
W powyższej funkcji wyrażenie regularne wzorca zostanie utworzone tylko raz, bez względu na to, ile razy funkcja zostanie wywołana.
Innym zastosowaniem jest utrzymywanie wystąpienia „losowego” w pobliżu:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Nie jest to również to samo, co zwykłe zadeklarowanie go jako współdzielonego członka klasy; Elementy zadeklarowane w ten sposób również są bezpieczne dla wątków. W tym scenariuszu nie ma to znaczenia, ponieważ wyrażenie nigdy się nie zmieni, ale są inne, gdzie może.
In vb jest różnica między tymi operatorami:
/
jest Double
\
to Integer
pomijając pozostałą
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
Bardzo podoba mi się „My” Namespace, która została wprowadzona w Visual Basic 2005. My to skrót do kilku grup informacji i funkcji. Zapewnia szybki i intuicyjny dostęp do następujących rodzajów informacji:
Chociaż rzadko jest przydatna, obsługa zdarzeń może być mocno dostosowana:
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
Można to następnie przetestować w następujący sposób:
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
Właśnie znalazłem artykuł mówiący o „!” operator, zwany także „operatorem wyszukiwania w słowniku”. Oto fragment artykułu pod adresem : http://panopticoncentral.net/articles/902.aspx
Techniczna nazwa! operator jest „operatorem wyszukiwania w słowniku”. Słownik to dowolny typ zbioru, który jest indeksowany za pomocą klucza, a nie liczby, tak jak sposób, w jaki wpisy w słowniku angielskim są indeksowane według słowa, którego definicję chcesz zdefiniować. Najpopularniejszym przykładem typu słownika jest System.Collections.Hashtable, który umożliwia dodawanie par (klucz, wartość) do tablicy hashy, a następnie pobieranie wartości za pomocą kluczy. Na przykład poniższy kod dodaje trzy wpisy do tablicy hashy i wyszukuje jeden z nich za pomocą klucza „Pork”.
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
The! operator może służyć do wyszukiwania wartości z dowolnego typu słownika, który indeksuje wartości przy użyciu ciągów. Identyfikator po! jest używany jako klucz w operacji wyszukiwania. Zatem powyższy kod mógłby zostać napisany:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
Drugi przykład jest całkowicie równoważny z pierwszym, ale po prostu wygląda o wiele ładniej, przynajmniej w moich oczach. Uważam, że jest wiele miejsc, w których! może być używany, zwłaszcza jeśli chodzi o XML i Internet, gdzie jest tylko mnóstwo kolekcji indeksowanych przez ciąg. Jednym niefortunnym ograniczeniem jest to, że rzecz następująca po! nadal musi być prawidłowym identyfikatorem, więc jeśli ciąg, którego chcesz użyć jako klucza, zawiera jakiś nieprawidłowy znak identyfikacyjny, nie możesz użyć! operator. (Nie możesz na przykład powiedzieć „Tabela! AB $ CD = 5”, ponieważ $ nie jest legalne w identyfikatorach). W wersji VB6 i wcześniejszych można używać nawiasów, aby uniknąć nieprawidłowych identyfikatorów (np. „Tabela! [AB $ CD] ”), ale kiedy zaczęliśmy używać nawiasów do zastępowania słów kluczowych, straciliśmy możliwość tego. W większości przypadków,
Aby uzyskać naprawdę techniczne, x! Y działa, jeśli x ma domyślną właściwość, która przyjmuje String lub Object jako parametr. W takim przypadku x! Y jest zamieniane na x.DefaultProperty ("y"). Ciekawostką na marginesie jest to, że w gramatyce leksykalnej języka istnieje specjalna reguła, która sprawia, że to wszystko działa. The! znak jest również używany jako znak typu w języku, a znaki typu są spożywane przed operatorami. Zatem bez specjalnej reguły x! Y byłby skanowany jako „x! Y” zamiast „x! Y”. Na szczęście, ponieważ w języku nie ma miejsca, w którym dwa identyfikatory w wierszu byłyby prawidłowe, wprowadziliśmy właśnie regułę, że jeśli następny znak po! jest początkiem identyfikatora, rozważamy! być operatorem, a nie znakiem typu.
Jest to wbudowane i stanowi zdecydowaną przewagę nad C #. Możliwość zaimplementowania metody interfejsu bez konieczności używania tej samej nazwy.
Jak na przykład:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
Wymuszanie ByVal
W VB, jeśli zawiniesz swoje argumenty w dodatkowym zestawie nawiasów, możesz przesłonić deklarację ByRef metody i przekształcić ją w ByVal. Na przykład poniższy kod daje 4, 5, 5 zamiast 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
Zobacz Argument niezmodyfikowany przez wywołanie procedury - zmienna bazowa
Przekazywanie parametrów według nazwy i zmiana ich kolejności
Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)
'Do stuff
End function
Stosowanie:
Module Module1
Sub Main()
MyFunc() 'No params specified
End Sub
End Module
Można go również wywołać przy użyciu specyfikacji parametru „: =” w dowolnej kolejności:
MyFunc(displayOrder:=10, msg:="mystring")
Instrukcja Using jest nowa od wersji VB 8, C # miała ją od początku. Wzywa do automatycznego usuwania.
Na przykład
Using lockThis as New MyLocker(objToLock)
End Using
Aliasy importu są również w dużej mierze nieznane:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Rozważ następującą deklarację zdarzenia
Public Event SomethingHappened As EventHandler
W języku C # można sprawdzić, czy subskrybenci zdarzeń są dostępni przy użyciu następującej składni:
if(SomethingHappened != null)
{
...
}
Jednak kompilator VB.NET tego nie obsługuje. W rzeczywistości tworzy ukryte prywatne pole członkowskie, które nie jest widoczne w IntelliSense:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Więcej informacji:
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
Jeśli chcesz, aby nazwa zmiennej pasowała do słowa kluczowego, umieść ją w nawiasach. Nie gdzie indziej. najlepsza praktyka - ale można ją mądrze stosować.
na przykład
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
np. przykład z komentarzy (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Istnieje kilka odpowiedzi dotyczących literałów XML, ale nie dotyczących tego konkretnego przypadku:
Możesz użyć literałów XML, aby ująć literały ciągów, które w innym przypadku wymagałyby zmiany znaczenia. Na przykład literały ciągów zawierające cudzysłowy.
Zamiast tego:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Możesz to zrobić:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Jest to szczególnie przydatne, jeśli testujesz literał do analizy CSV:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(Oczywiście nie musisz używać <string>
tagu; możesz użyć dowolnego tagu, który chcesz).
<q>
byłby dobrym tagiem, podobnym do użycia w Perlu / Ruby. W każdym razie to całkiem niezły idiom. LUBIĆ!
DateTime można zainicjować, otaczając datę #
Dim independanceDay As DateTime = #7/4/1776#
Możesz również użyć wnioskowania o typie razem z tą składnią
Dim independanceDay = #7/4/1776#
To o wiele przyjemniejsze niż użycie konstruktora
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Możesz mieć 2 linie kodu w jednej linii. W związku z tym:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Parametry opcjonalne
Opcje są o wiele łatwiejsze niż tworzenie nowych przeciążeń, takich jak:
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
Przypadek tytułu w VB.Net można uzyskać za pomocą starego fxn VB6:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Właściwości z parametrami
Zajmowałem się programowaniem w C # i odkryłem brakującą funkcję, którą miał VB.Net, ale nie została tutaj wspomniana.
Przykład, jak to zrobić (a także ograniczenie języka C # ) można zobaczyć na stronie: Używanie typowych właściwości get set w C # ... with parameters
Wyciągnąłem kod z tej odpowiedzi:
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