Ho imparato un bel po 'sfogliando le funzionalità nascoste di C # e sono rimasto sorpreso quando non sono riuscito a trovare qualcosa di simile per VB.NET.
Quindi quali sono alcune delle sue caratteristiche nascoste o meno conosciute?
Ho imparato un bel po 'sfogliando le funzionalità nascoste di C # e sono rimasto sorpreso quando non sono riuscito a trovare qualcosa di simile per VB.NET.
Quindi quali sono alcune delle sue caratteristiche nascoste o meno conosciute?
Risposte:
La Exception When
clausola è in gran parte sconosciuta.
Considera questo:
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
sUna delle vere caratteristiche nascoste di VB è il completionlist
tag di documentazione XML che può essere utilizzato per creare Enum
tipi propri con funzionalità estese. Tuttavia, questa funzionalità non funziona in C #.
Un esempio da un mio codice recente:
'
''' <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
Ora, quando si assegna un valore a una variabile dichiarata come Rule
, l'IDE offre un elenco IntelliSense di possibili valori da RuleTemplates
.
Poiché questa è una funzionalità che si basa sull'IDE, è difficile mostrare come appare quando la usi, ma userò solo uno screenshot:
Elenco di completamento in azione http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
In effetti, IntelliSense è identico al 100% a quello che ottieni quando usi un file Enum
.
friend
o usando la stessa classe dell'enum: Rule
invece di RuleTemplate
.
Hai notato l'operatore di confronto Like?
Dim b As Boolean = "file.txt" Like "*.txt"
Altro da 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 conosce un tipo primitivo di alias typedef
via Import
:
Imports S = System.String
Dim x As S = "Hello"
Questo è più utile se usato insieme a tipi generici:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
dovrebbe essere. ;-) In qualche modo, questo errore è passato inosservato (e ha ottenuto 28 voti positivi) per quasi un anno intero.
Imports Assert = xUnit.Assert
Oh! e non dimenticare i letterali 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
(Ho trovato questo particolarmente utile durante la scrittura di test su parsing file CSV in cui ogni campo è stato tra virgolette Sarebbe. Non stato divertente per sfuggire tutte quelle citazioni a mano nel mio linee di prova.)
C'è anche l'inizializzazione degli oggetti!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
è una meraviglia. In superficie, funziona in modo simile CType
all'operatore in quanto converte un oggetto da un tipo a un altro. Tuttavia, funziona secondo una serie di regole molto più rigide. CType
L'effettivo comportamento è quindi spesso opaco e non è affatto evidente quale tipo di conversione viene eseguita.
DirectCast
supporta solo due operazioni distinte:
Qualsiasi altro cast non funzionerà (ad esempio, tentando di decomprimere un Integer
in a Double
) e risulterà in un errore in fase di compilazione / runtime (a seconda della situazione e di ciò che può essere rilevato dal controllo del tipo statico). Pertanto lo uso DirectCast
ogni volta che è possibile, poiché questo cattura al meglio il mio intento: a seconda della situazione, desidero estrarre un valore di tipo noto o eseguire un upcast. Fine della storia.
L'utilizzo CType
, d'altra parte, lascia il lettore del codice a chiedersi cosa intendesse veramente il programmatore perché risolve tutti i tipi di operazioni diverse, inclusa la chiamata di codice definito dall'utente.
Perché questa è una caratteristica nascosta? Il team di VB ha pubblicato una linea guida 1 che ne scoraggia l'uso DirectCast
(anche se in realtà è più veloce!) Per rendere il codice più uniforme. Ritengo che questa sia una cattiva linea guida che dovrebbe essere invertita: quando possibile, favorisci DirectCast
l' CType
operatore più generale . Rende il codice molto più chiaro. CType
, d'altra parte, dovrebbe essere chiamato solo se questo è davvero inteso, cioè quando dovrebbe essere chiamato un CType
operatore di restringimento (cfr. sovraccarico di operatori ).
1) Non riesco a trovare un collegamento alla linea guida ma ho trovato l' opinione di Paul Vick (capo sviluppatore del team VB):
Nel mondo reale, non noterai quasi mai la differenza, quindi potresti anche optare per operatori di conversione più flessibili come CType, CInt, ecc.
(EDIT by Zack: Ulteriori informazioni qui: come devo eseguire il cast in VB.NET? )
TryCast
allora poiché avevo principalmente un osso da scegliere con l'uso pervasivo CType
.
TryCast
funzionano solo sui tipi di riferimento, come da documentazione.
If
operatore condizionale e coalesceNon so come lo chiameresti nascosto, ma la funzione Iif ([espressione], [valore se vero], [valore se falso]) As Oggetto potrebbe contare.
Non è tanto nascosto quanto deprecato ! VB 9 ha l' If
operatore che è molto migliore e funziona esattamente come l'operatore condizionale e coalesce di C # (a seconda di ciò che si desidera):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Modificato per mostrare un altro esempio:
Funzionerà con If()
, ma causerà un'eccezione conIIf()
Dim x = If(b<>0,a/b,0)
:?
operatore di Perl , non è solo una versione semplificata.
Questo è carino. L'istruzione Select Case all'interno di VB.Net è molto potente.
Certo che c'è lo standard
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Ma c'è di più ...
Puoi fare intervalli:
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
E anche di più...
Puoi (anche se potrebbe non essere una buona idea) eseguire controlli booleani su più variabili:
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
è che sembra che valuti ciascuna delle Case
affermazioni ed esegua il codice per ognuna che è vera. Ma in realtà li valuta uno per uno e esegue il codice solo per il primo che è vero. La sintassi per If
è molto più chiara a questo proposito ( If...Else If...Else If...Else
).
Un importante risparmio di tempo che uso sempre è la parola chiave With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
Semplicemente non mi piace scrivere più di quanto devo!
Il migliore e facile parser CSV:
Microsoft.VisualBasic.FileIO.TextFieldParser
Aggiungendo un riferimento a Microsoft.VisualBasic, questo può essere utilizzato in qualsiasi altro linguaggio .Net, ad esempio C #
(EDIT: Ulteriori informazioni qui: dovrei usare sempre gli operatori AndAlso e OrElse? )
Membri statici nei metodi.
Per esempio:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
Nella funzione precedente, l'espressione regolare del modello verrà creata solo una volta, indipendentemente da quante volte viene chiamata la funzione.
Un altro utilizzo è mantenere un'istanza di "random" in giro:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Inoltre, questo non è la stessa cosa che dichiararlo semplicemente come membro condiviso della classe; gli elementi dichiarati in questo modo sono garantiti anche thread-safe. Non importa in questo scenario poiché l'espressione non cambierà mai, ma ce ne sono altre in cui potrebbe.
In vb c'è una differenza tra questi operatori:
/
si Double
\
è Integer
ignorando il resto
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
Mi piace molto lo spazio dei nomi "My" che è stato introdotto in Visual Basic 2005. My è un collegamento a diversi gruppi di informazioni e funzionalità. Fornisce un accesso rapido e intuitivo ai seguenti tipi di informazioni:
Sebbene raramente utile, la gestione degli eventi può essere fortemente personalizzata:
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
Questo può quindi essere testato nel modo seguente:
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
Ho appena trovato un articolo che parla del "!" operatore, noto anche come "operatore di ricerca nel dizionario". Ecco un estratto dell'articolo su: http://panopticoncentral.net/articles/902.aspx
Il nome tecnico per il! operatore è l '"operatore di ricerca nel dizionario". Un dizionario è un tipo di raccolta indicizzato da una chiave anziché da un numero, proprio come le voci di un dizionario inglese sono indicizzate dalla parola di cui si desidera la definizione. L'esempio più comune di un tipo di dizionario è System.Collections.Hashtable, che consente di aggiungere coppie (chiave, valore) nella tabella hash e quindi recuperare i valori utilizzando le chiavi. Ad esempio, il codice seguente aggiunge tre voci a una tabella hash e ne cerca una utilizzando la chiave "Pork".
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
Il ! L'operatore può essere utilizzato per cercare i valori da qualsiasi tipo di dizionario che ne indicizza i valori utilizzando le stringhe. L'identificatore dopo il! viene utilizzato come chiave nell'operazione di ricerca. Quindi il codice sopra potrebbe invece essere stato scritto:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
Il secondo esempio è completamente equivalente al primo, ma sembra molto più carino, almeno ai miei occhi. Trovo che ci siano molti posti dove! può essere utilizzato, soprattutto quando si tratta di XML e web, dove ci sono solo tonnellate di raccolte indicizzate per stringa. Una sfortunata limitazione è che la cosa che segue! deve ancora essere un identificatore valido, quindi se la stringa che vuoi usare come chiave contiene un carattere identificativo non valido, non puoi usare il! operatore. (Non puoi, ad esempio, dire "Tabella! AB $ CD = 5" perché $ non è legale negli identificatori.) In VB6 e versioni precedenti, potresti usare le parentesi per sfuggire agli identificatori non validi (ad esempio "Tabella! [AB $ CD] "), ma quando abbiamo iniziato a utilizzare le parentesi per sfuggire alle parole chiave, abbiamo perso la capacità di farlo. Nella maggior parte dei casi,
Per essere davvero tecnici, x! Y funziona se x ha una proprietà predefinita che accetta una stringa o un oggetto come parametro. In tal caso, x! Y viene modificato in x.DefaultProperty ("y"). Una nota a margine interessante è che c'è una regola speciale nella grammatica lessicale della lingua per far funzionare tutto questo. Il ! Il carattere viene utilizzato anche come carattere di tipo nella lingua e i caratteri di tipo vengono mangiati prima degli operatori. Quindi, senza una regola speciale, x! Y verrebbe scansionato come "x! Y" invece di "x! Y". Fortunatamente, poiché non c'è posto nella lingua in cui due identificatori di fila siano validi, abbiamo appena introdotto la regola che se il carattere successivo dopo! è l'inizio di un identificatore, consideriamo il! essere un operatore e non un carattere di tipo.
Questo è integrato e rappresenta un netto vantaggio rispetto a C #. La possibilità di implementare un metodo di interfaccia senza dover utilizzare lo stesso nome.
Ad esempio:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
Forzare ByVal
In VB, se racchiudi i tuoi argomenti in un set aggiuntivo di parentesi, puoi sovrascrivere la dichiarazione ByRef del metodo e trasformarla in ByVal. Ad esempio, il codice seguente produce 4, 5, 5 invece di 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
Vedere Argomento non modificato dalla chiamata di procedura - Variabile sottostante
Passare i parametri per nome e, quindi, riordinarli
Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)
'Do stuff
End function
Uso:
Module Module1
Sub Main()
MyFunc() 'No params specified
End Sub
End Module
Può anche essere chiamato utilizzando la specifica del parametro ": =" in qualsiasi ordine:
MyFunc(displayOrder:=10, msg:="mystring")
L'istruzione Using è nuova a partire da VB 8, C # l'aveva dall'inizio. Chiama dispose automagicamente per te.
Per esempio
Using lockThis as New MyLocker(objToLock)
End Using
Anche gli alias di importazione sono in gran parte sconosciuti:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Considera la seguente dichiarazione di evento
Public Event SomethingHappened As EventHandler
In C # è possibile verificare la presenza di sottoscrittori di eventi utilizzando la sintassi seguente:
if(SomethingHappened != null)
{
...
}
Tuttavia, il compilatore VB.NET non lo supporta. In realtà crea un campo membro privato nascosto che non è visibile in IntelliSense:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Maggiori informazioni:
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
Se hai bisogno di un nome di variabile che corrisponda a quello di una parola chiave, racchiudilo tra parentesi. Non nca. la migliore pratica, tuttavia, ma può essere utilizzata con saggezza.
per esempio
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
ad es. Esempio dai commenti (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Ci sono un paio di risposte sui valori letterali XML, ma non su questo caso specifico:
È possibile utilizzare valori letterali XML per racchiudere valori letterali stringa che altrimenti dovrebbero essere sottoposti a escape. Valori letterali stringa che contengono virgolette doppie, ad esempio.
Invece di questo:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Puoi farlo:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Ciò è particolarmente utile se stai testando un letterale per l'analisi CSV:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(Non devi usare il <string>
tag, ovviamente; puoi usare qualsiasi tag che ti piace.)
<q>
sarebbe un buon tag, simile all'uso in Perl / Ruby. Comunque, è un bel modo di dire. PIACE!
DateTime può essere inizializzato circondando la data con #
Dim independanceDay As DateTime = #7/4/1776#
Puoi anche usare l'inferenza del tipo insieme a questa sintassi
Dim independanceDay = #7/4/1776#
È molto più bello che usare il costruttore
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Puoi avere 2 righe di codice in una sola riga. quindi:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Parametri opzionali
Gli optionals sono molto più facili rispetto alla creazione di nuovi overload, come ad esempio:
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
Il caso del titolo in VB.Net può essere ottenuto da un vecchio fxn VB6:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Proprietà con parametri
Ho fatto un po 'di programmazione C # e ho scoperto una funzionalità che mancava che VB.Net aveva, ma non è stata menzionata qui.
Un esempio di come eseguire questa operazione (così come la limitazione di c #) può essere visto in: Uso delle tipiche proprietà get set in C # ... con parametri
Ho estratto il codice da quella risposta:
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