J'ai beaucoup appris à parcourir les fonctionnalités cachées de C # et j'ai été surpris de ne pas trouver quelque chose de similaire pour VB.NET.
Alors, quelles sont certaines de ses fonctionnalités cachées ou moins connues?
J'ai beaucoup appris à parcourir les fonctionnalités cachées de C # et j'ai été surpris de ne pas trouver quelque chose de similaire pour VB.NET.
Alors, quelles sont certaines de ses fonctionnalités cachées ou moins connues?
Réponses:
La Exception When
clause est largement inconnue.
Considère ceci:
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 personnaliséL'une des véritables fonctionnalités cachées de VB est la completionlist
balise de documentation XML qui peut être utilisée pour créer des Enum
types similaires avec des fonctionnalités étendues. Cette fonctionnalité ne fonctionne pas en C #, cependant.
Un exemple d'un de mes codes récents:
'
''' <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
Désormais, lors de l'affectation d'une valeur à une variable déclarée comme Rule
, l'EDI propose une liste IntelliSense des valeurs possibles de RuleTemplates
.
Comme il s'agit d'une fonctionnalité qui repose sur l'EDI, il est difficile de montrer à quoi cela ressemble lorsque vous l'utilisez, mais je vais simplement utiliser une capture d'écran:
Liste de complétion en action http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
En fait, IntelliSense est 100% identique à ce que vous obtenez en utilisant un Enum
.
friend
ou en utilisant la même classe que l'énumération: Rule
au lieu de RuleTemplate
.
Avez-vous remarqué l'opérateur de comparaison Like?
Dim b As Boolean = "file.txt" Like "*.txt"
En savoir plus sur 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 connaît un type primitif d' alias typedef
via Import
:
Imports S = System.String
Dim x As S = "Hello"
Ceci est plus utile lorsqu'il est utilisé avec des types génériques:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
ça devrait être. ;-) D'une manière ou d'une autre, cette erreur n'a pas été détectée (et a recueilli 28 votes positifs) pendant près d'un an.
Imports Assert = xUnit.Assert
Oh! et n'oubliez pas les littéraux 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
(J'ai trouvé cela particulièrement pratique lors de l'écriture de tests sur l'analyse de fichiers CSV où chaque champ était entre guillemets. Cela n'aurait pas été amusant d'échapper à toutes ces citations à la main dans mon test lines.)
L'initialisation d'objet est là aussi!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
est une merveille. En surface, il fonctionne de manière similaire à l' CType
opérateur en ce sens qu'il convertit un objet d'un type en un autre. Cependant, cela fonctionne selon un ensemble de règles beaucoup plus strictes.CType
Le comportement réel de ce dernier est donc souvent opaque et on ne sait pas du tout quel type de conversion est exécuté.
DirectCast
ne prend en charge que deux opérations distinctes:
Tout autre cast ne fonctionnera pas (par exemple, essayer de déballer un Integer
en a Double
) et entraînera une erreur de compilation / exécution (en fonction de la situation et de ce qui peut être détecté par la vérification de type statique). J'utilise doncDirectCast
autant que possible, car cela capture au mieux mon intention: selon la situation, je souhaite soit déballer une valeur de type connu, soit effectuer un upcast. Fin de l'histoire.
L'utilisation CType
, par contre, laisse le lecteur du code se demander ce que le programmeur a vraiment voulu car il résout toutes sortes d'opérations différentes, y compris l'appel de code défini par l'utilisateur.
Pourquoi est-ce une fonctionnalité cachée? L'équipe VB a publié une directive 1 qui décourage l'utilisation de DirectCast
(même si c'est en fait plus rapide!) Afin de rendre le code plus uniforme. Je soutiens que c'est une mauvaise directive qui devrait être inversée: autant que possible, privilégiez DirectCast
l' CType
opérateur plus général . Cela rend le code beaucoup plus clair.CType
, d'autre part, ne doit être appelé que si c'est effectivement prévu, c'est-à-dire lorsqu'un CType
opérateur de rétrécissement (cf. surcharge d'opérateur ) doit être appelé.
1) Je suis incapable de trouver un lien vers la ligne directrice, mais j'ai trouvé le point de vue de Paul Vick (développeur en chef de l'équipe VB):
Dans le monde réel, vous ne remarquerez presque jamais la différence, alors autant opter pour les opérateurs de conversion plus flexibles comme CType, CInt, etc.
(EDIT by Zack: En savoir plus ici: Comment puis-je diffuser dans VB.NET? )
TryCast
à l'époque car j'avais principalement un os à choisir avec l'utilisation généralisée de CType
.
TryCast
ne fonctionnent que sur les types référence, selon la documentation.
If
opérateur conditionnel et de fusionJe ne sais pas comment vous l'appelleriez caché, mais la fonction Iif ([expression], [valeur si vraie], [valeur si fausse]) As Object pourrait compter.
Ce n'est pas tant caché que obsolète ! VB 9 a l' If
opérateur qui est bien meilleur et fonctionne exactement comme l'opérateur conditionnel et de fusion de C # (selon ce que vous voulez):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Modifié pour montrer un autre exemple:
Cela fonctionnera avec If()
, mais provoquera une exception avecIIf()
Dim x = If(b<>0,a/b,0)
:?
opérateur C et Perl , ce n'est pas seulement une version simplifiée.
C'est une belle. L'instruction Select Case dans VB.Net est très puissante.
Bien sûr, il y a la norme
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Mais il y a plus ...
Vous pouvez faire des gammes:
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
Et encore plus...
Vous pouvez (bien que ce ne soit pas une bonne idée) faire des vérifications booléennes sur plusieurs variables:
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
est qu'il semble qu'il évalue chacune des Case
instructions et exécute le code pour chacune d'elles qui est vraie. Mais en fait, il les évalue un par un et n'exécute le code que pour le premier qui est vrai. La syntaxe de If
est beaucoup plus claire à cet égard ( If...Else If...Else If...Else
).
Un gain de temps majeur que j'utilise tout le temps est le mot clé With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
Je n'aime tout simplement pas taper plus que nécessaire!
L'analyseur CSV le meilleur et le plus simple:
Microsoft.VisualBasic.FileIO.TextFieldParser
En ajoutant une référence à Microsoft.VisualBasic, cela peut être utilisé dans n'importe quel autre langage .Net, par exemple C #
(EDIT: En savoir plus ici: Dois-je toujours utiliser les opérateurs AndAlso et OrElse? )
Membres statiques dans les méthodes.
Par exemple:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
Dans la fonction ci-dessus, l'expression régulière de modèle ne sera créée qu'une seule fois, quel que soit le nombre d'appels de la fonction.
Une autre utilisation est de conserver une instance de "aléatoire" autour de:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
En outre, ce n'est pas la même chose que de simplement le déclarer en tant que membre partagé de la classe; les éléments déclarés de cette façon sont également garantis pour les threads. Cela n'a pas d'importance dans ce scénario car l'expression ne changera jamais, mais il y en a d'autres où cela pourrait.
Dans vb, il y a une différence entre ces opérateurs:
/
on Double
\
est en Integer
ignorant le reste
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
J'aime beaucoup l' espace de noms «Mon» qui a été introduit dans Visual Basic 2005. My est un raccourci vers plusieurs groupes d'informations et de fonctionnalités. Il offre un accès rapide et intuitif aux types d'informations suivants:
Bien que rarement utile, la gestion des événements peut être fortement personnalisée:
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
Cela peut ensuite être testé de la manière suivante:
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
Je viens de trouver un article sur le "!" opérateur, également appelé «opérateur de recherche de dictionnaire». Voici un extrait de l'article à l' adresse : http://panopticoncentral.net/articles/902.aspx
Le nom technique du! L'opérateur est «l'opérateur de recherche de dictionnaire». Un dictionnaire est tout type de collection indexé par une clé plutôt que par un nombre, tout comme la façon dont les entrées d'un dictionnaire anglais sont indexées par le mot dont vous voulez la définition. L'exemple le plus courant d'un type de dictionnaire est System.Collections.Hashtable, qui vous permet d'ajouter des paires (clé, valeur) dans la table de hachage, puis de récupérer des valeurs à l'aide des clés. Par exemple, le code suivant ajoute trois entrées à une table de hachage et recherche l'une d'elles à l'aide de la clé «Pork».
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
Le ! L'opérateur peut être utilisé pour rechercher des valeurs à partir de n'importe quel type de dictionnaire qui indexe ses valeurs à l'aide de chaînes. L'identifiant après le! est utilisé comme clé dans l'opération de recherche. Ainsi, le code ci-dessus aurait pu être écrit à la place:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
Le deuxième exemple est tout à fait équivalent au premier, mais semble beaucoup plus joli, du moins à mes yeux. Je trouve qu'il y a beaucoup d'endroits où! peut être utilisé, en particulier lorsqu'il s'agit de XML et du Web, où il n'y a que des tonnes de collections indexées par chaîne. Une limitation malheureuse est que la chose qui suit le! doit toujours être un identifiant valide, donc si la chaîne que vous souhaitez utiliser comme clé contient un caractère identifiant non valide, vous ne pouvez pas utiliser le! opérateur. (Vous ne pouvez pas, par exemple, dire "Table! AB $ CD = 5" car $ n'est pas légal dans les identifiants.) Dans VB6 et avant, vous pouvez utiliser des crochets pour échapper les identifiants invalides (par exemple "Table! [AB $ CD] "), mais lorsque nous avons commencé à utiliser des crochets pour échapper des mots-clés, nous avons perdu la possibilité de le faire. Dans la plupart des cas,
Pour être vraiment technique, x! Y fonctionne si x a une propriété par défaut qui prend une chaîne ou un objet comme paramètre. Dans ce cas, x! Y est changé en x.DefaultProperty ("y"). Une note latérale intéressante est qu'il existe une règle spéciale dans la grammaire lexicale de la langue pour que tout cela fonctionne. Le ! Le caractère est également utilisé comme caractère de type dans la langue, et les caractères de type sont mangés avant les opérateurs. Donc, sans règle spéciale, x! Y serait scanné comme "x! Y" au lieu de "x! Y". Heureusement, comme il n'y a aucun endroit dans la langue où deux identifiants d'affilée sont valides, nous venons d'introduire la règle selon laquelle si le caractère suivant après le! est le début d'un identifiant, on considère le! être un opérateur et non un caractère de type.
Ceci est intégré et constitue un avantage certain par rapport à C #. La possibilité d'implémenter une méthode d'interface sans avoir à utiliser le même nom.
Tel que:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
Forcer ByVal
Dans VB, si vous encapsulez vos arguments dans un ensemble supplémentaire de parenthèses, vous pouvez remplacer la déclaration ByRef de la méthode et la transformer en ByVal. Par exemple, le code suivant produit 4, 5, 5 au lieu de 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
Voir l' argument non modifié par l'appel de procédure - Variable sous-jacente
Passer des paramètres par nom et donc les réorganiser
Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)
'Do stuff
End function
Usage:
Module Module1
Sub Main()
MyFunc() 'No params specified
End Sub
End Module
Peut également être appelé à l'aide de la spécification du paramètre ": =" dans n'importe quel ordre:
MyFunc(displayOrder:=10, msg:="mystring")
L'instruction Using est nouvelle à partir de VB 8, C # l'avait depuis le début. Il appelle à disposer automatiquement pour vous.
Par exemple
Using lockThis as New MyLocker(objToLock)
End Using
Les alias d'importation sont également largement inconnus:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Considérez la déclaration d'événement suivante
Public Event SomethingHappened As EventHandler
En C #, vous pouvez rechercher des abonnés à l'événement en utilisant la syntaxe suivante:
if(SomethingHappened != null)
{
...
}
Toutefois, le compilateur VB.NET ne prend pas en charge cela. Il crée en fait un champ de membre privé caché qui n'est pas visible dans IntelliSense:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Plus d'information:
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
Si vous avez besoin d'un nom de variable correspondant à celui d'un mot-clé, placez-le entre crochets. Pas nec. la meilleure pratique cependant - mais elle peut être utilisée à bon escient.
par exemple
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
Exemple à partir des commentaires (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Il y a quelques réponses sur les littéraux XML, mais pas sur ce cas spécifique:
Vous pouvez utiliser des littéraux XML pour entourer des littéraux de chaîne qui devraient autrement être échappés. Des chaînes littérales contenant des guillemets doubles, par exemple.
Au lieu de cela:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Tu peux le faire:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Ceci est particulièrement utile si vous testez un littéral pour l'analyse CSV:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(Vous n'êtes pas obligé d'utiliser la <string>
balise, bien sûr; vous pouvez utiliser n'importe quelle balise que vous aimez.)
<q>
serait une bonne balise, similaire à l'utilisation en Perl / Ruby. Quoi qu'il en soit, c'est un idiome assez sympa. COMME!
DateTime peut être initialisé en entourant votre date avec #
Dim independanceDay As DateTime = #7/4/1776#
Vous pouvez également utiliser l'inférence de type avec cette syntaxe
Dim independanceDay = #7/4/1776#
C'est beaucoup plus agréable que d'utiliser le constructeur
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Vous pouvez avoir 2 lignes de code sur une seule ligne. Par conséquent:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Paramètres facultatifs
Les options sont tellement plus faciles que de créer de nouvelles surcharges, telles que:
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
La casse de titre dans VB.Net peut être obtenue par un ancien fxn VB6:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Propriétés avec paramètres
J'ai fait de la programmation C # et découvert une fonctionnalité qui manquait à VB.Net, mais qui n'a pas été mentionnée ici.
Un exemple de comment faire cela (ainsi que la limitation c #) peut être vu à: Utilisation des propriétés get set typiques en C # ... avec des paramètres
J'ai extrait le code de cette réponse:
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