Fonctionnalités cachées de VB.NET?

121

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?

Sean Gough
la source

Réponses:

128

La Exception Whenclause 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
torial
la source
9
utile si vous souhaitez attraper une SQLException spécifique, disons -2 qui, si je me souviens bien, est le délai d'expiration du réseau: Catch ex comme sqlException où ex.code = -2
Pondidum
Hou la la! Je viens de lire ceci et de l'utiliser immédiatement pour simplifier un bloc try / catch que je viens d'écrire la semaine dernière. Je n'ai jamais su que cela existait.
John M Gant le
1
1 Et voici où le blog de l' équipe CLR NET explique pourquoi les filtres d'exception sont utiles blogs.msdn.com/clrteam/archive/2009/02/05/...
MarkJ
5
Non seulement cela est caché, mais il n'est pas non plus disponible en C #.
Cheeso
82

EnumS personnalisé

L'une des véritables fonctionnalités cachées de VB est la completionlistbalise de documentation XML qui peut être utilisée pour créer des Enumtypes 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.

/ÉDITER:

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.

Konrad Rudolph
la source
Intéressant - pourriez-vous montrer un exemple de ce à quoi cela ressemble lorsque vous le consommez?
Brian MacKay le
Il semble que quelqu'un puisse toujours créer sa propre règle en appelant directement le constructeur de règles? Si oui, et si vous vouliez arrêter cela, pourriez-vous déclarer le constructeur comme "Friend" dans votre bibliothèque?
Joel Coehoorn
Joel, dans mon exemple de code, je n'ai pas intentionnellement interdit cela. Je propose plutôt à l'utilisateur des règles communes et autorise la création de règles propres et spécialisées. Vous pouvez bien sûr éviter cela en marquant le constructeur comme friendou en utilisant la même classe que l'énumération: Ruleau lieu de RuleTemplate.
Konrad Rudolph
y a-t-il quelque part une liste des utilisations des attributs utiles cachés? celui-ci semble incroyable, mais je ne sais pas encore où je l'utiliserais ou s'il pourrait résoudre un problème primaire dans certains cas sans avoir la possibilité d'avoir un générique limité aux énumérations.
Maslow
@Maslow: il n'y a pas d'attribut impliqué ici. C'est un commentaire xml.
Joel Coehoorn le
49

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*"
Eduardo Molteni
la source
3
attends quoi? C'est nouveau pour moi! Hmm, c'est vraiment mieux que l'alternative avec la manipulation de chaînes VB.NET: D
STW
.. !! Je ne le savais pas bien que j'ai travaillé sur plusieurs projets vb.net! Fonctionnalité intéressante ...
Meta-Knight
woooooooooooooooooooooooow! Merci! c'est extraordinaire! ça marche aussi dans ELinq, DLinq? qu'en est-il de XLinq?
Shimmy Weitzhandler le
@dotjoe Hmm? Il n'y a rien de «paresseux» dans ces globes.
Josh Lee
Comment cela fonctionne-t-il, que se passe-t-il sous le capot? Est-ce synonyme de bibliothèques reg ex?
brumScouse
48

Typedefs

VB connaît un type primitif d' alias typedefvia 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)
Konrad Rudolph
la source
2
s'il vous plaît montrer un exemple le mot Importer n'est pas reconnu dans mon IDE.
Shimmy Weitzhandler
5
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.
Konrad Rudolph
Je me suis toujours demandé comment je pourrais créer un nouveau "type" avec des valeurs par défaut pour un générique! Cool!
eidylon le
3
Importez, importez, importez, peu importe! Sheesh, vous pensez que nous avons lu ces messages avant de les voter!
MarkJ le
Superbe pour utiliser xunit dans les tests de studio visuel ieImports Assert = xUnit.Assert
wheelibin
45

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>
Nescio
la source
C'est ce que j'allais dire. En fait, j'ai utilisé des littéraux XML dans un but pour lequel ce n'était pas prévu. Je l'ai utilisé pour produire du Javascript ... swortham.blogspot.com/2009/03/vb-2008.html
Steve Wortham
9
Entre autres choses, vous pouvez utiliser des littéraux XML pour contourner les échappements de chaînes laides, par exemple lorsque vous utilisez des chaînes contenant elles-mêmes des guillemets doubles. Il suffit de mettre la chaîne dans un littéral XML et d'appeler Value, comme ceci: <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.)
Ryan Lundy
2
@Kyralessa: +1, excellent commentaire. En fait, c'est aussi un excellent moyen de spécifier des chaînes multilignes (embrasse les instructions SQL, etc.).
Heinzi
Inline XML est l'une des pires fonctionnalités de VB.NET jamais conçues. Fait non étayé.
Grant Thomas
39

L'initialisation d'objet est là aussi!

Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
Nescio
la source
1
Je ne peux pas croire qu'ils soient allés avec des bretelles bouclées. Nous avons déjà une instruction With .. ils auraient pu simplement réutiliser cette syntaxe.
Sam Axe
2
Je sais, c'est juste pour te montrer qu'il n'y a pas de flic sur la route ... lol JK
Shimmy Weitzhandler
4
C'est ce qui se passe lorsque tous les auteurs du compilateur sont eux-mêmes des programmeurs C / C ++ dans l'âme. Ils continuent à glisser la syntaxe C dans d'autres langages parce qu'ils ne peuvent pas concevoir que quelque chose soit mieux.
RBarryYoung
38

DirectCast

DirectCastest une merveille. En surface, il fonctionne de manière similaire à l' CTypeopé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.CTypeLe 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:

  • Déballage d'un type valeur, et
  • upcasting dans la hiérarchie des classes.

Tout autre cast ne fonctionnera pas (par exemple, essayer de déballer un Integeren 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 DirectCastl' CTypeopé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 CTypeopé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? )

Konrad Rudolph
la source
J'aime vraiment TryCast () un peu mieux. Il ne lèvera pas d'exception, renvoyez simplement Nothing si le cast échoue. Si vous vous attendez à ce que la distribution échoue souvent, c'est plus rapide que If TypeOf x Is T ... DirectCast (x, T) et certainement plus rapide que de capturer l'exception si DirectCast échoue.
Bob King
6
DirectCast () et TryCast () sont inestimables lorsqu'ils sont utilisés correctement en tant que paire. DirectCast () doit être utilisé si l'objet en cours de conversion est toujours censé être le type cible (si ce n'est pas le cas, vous obtiendrez une erreur, une bonne chose car c'est une situation inattendue). TryCast () doit être utilisé si l'objet en cours de conversion peut être du type cible ou de plusieurs types de cible. L'utilisation exclusive de l'un ou de l'autre entraînera soit une surcharge supplémentaire (si typeof x est y, alors la diffusion directe (x, y) est inefficace) soit éviter les erreurs valides (en utilisant TryCast () pour les cas où l'objet doit toujours être le type cible)
STW
Yoooder: 100% correct. C'est dommage que je n'ai pas mentionné TryCastà l'époque car j'avais principalement un os à choisir avec l'utilisation généralisée de CType.
Konrad Rudolph
@Maslow: bien sûr que non, car les Enums sont des types valeur et TryCastne fonctionnent que sur les types référence, selon la documentation.
Konrad Rudolph
+1: Heh. Je dois admettre que je viens de lire ceci et je me suis dit "Oh ouais, DirectCast, comment ai-je oublié ça?" Et puis je l'ai utilisé sur ma toute prochaine ligne de code (car je n'aime vraiment pas CType).
RBarryYoung
37

If opérateur conditionnel et de fusion

Je 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' Ifopé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)
Konrad Rudolph
la source
Bien, je ne savais pas ça! Je viens d'utiliser IIF hier, je vais donc revoir ce bloc de code.
Sean Gough
4
Dites cela à VS 2005. Nous ne travaillons pas tous avec les derniers et les meilleurs.
Sam Erwin
3
@Slough, absurdité. Cette méthode est de type sûr à 100% et renvoie un objet du même type que son (deuxième et troisième) argument. De plus, il doit y avoir une conversion élargie entre les arguments, sinon il y aura une erreur de compilation car les types ne correspondent pas.
Konrad Rudolph
1
Oui, c'est IIf () qui n'est pas de type sûr
Pondidum
2
@ Br.Bill En fait, c'est tout à fait équivalent à l' :?opérateur C et Perl , ce n'est pas seulement une version simplifiée.
Konrad Rudolph
32

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
torial
la source
5
En fait, vous en avez manqué quelques-uns: a) utilisation de "Select Case True" pour tester plus d'une variable, b) utilisation du formulaire "Case A, B, ...", et même c) application du ":" à in aligner l'instruction d'exécution avec la clause condition (bien que beaucoup n'aiment pas ça).
RBarryYoung
6
Veuillez ne pas utiliser Select Case True. Utilisez simplement une instruction If.
Ryan Lundy
4
Je trouve Select Case True beaucoup plus facile à lire qu'une déclaration ifelse géante.
dwidel
Le problème avec Select Case Trueest qu'il semble qu'il évalue chacune des Caseinstructions 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 Ifest beaucoup plus claire à cet égard ( If...Else If...Else If...Else).
Ryan Lundy
31

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!

Jasha87
la source
Mais cela crée aussi des bugs cachés, surtout quand vous avez With within With
Varun Mahajan
2
Je ne savais même pas que vous pouviez mettre un nouveau avec dans un avec existant. C'est juste bâclé!
Bob King du
2Bob: ce n'est pas bâclé, je dirais ... c'est juste une construction de langage à utiliser avec précaution. Pour définir de nombreuses propriétés dans des lignes successives, c'est génial, mais trouver un .Foo aléatoire dans un morceau de code complexe, puis devoir chasser les lignes de l'instruction With x ci-dessus n'est pas une bonne utilisation de la fonctionnalité.
ChrisA
2
Souhaitez-vous que C # l'ait? Ou est-ce que je dormais et est-ce que dans les réponses C # fonctionnalités cachées déjà ...? ;-)
peSHIr
1
@Boo: Vous avez raison, mais c'est toujours ennuyeux que vous ne puissiez pas l'ajouter à la liste de surveillance.
Meta-Knight
31

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 #

cjk
la source
5
+1 C'est bizarre comment les gens de C # courent vers FileHelpers sans jamais en tenir compte. Je suis sûr que FileHelpers est excellent, mais c'est une dépendance externe.
MarkJ
@MarkJ Je présume que c'est à cause de l'ignorance
Nathan Koop
J'ai fouillé sur Google pour essayer de trouver cette classe et je ne l'ai jamais fait, merci de l'avoir fait exploser!
pingoo
26
  • Opérateurs logiques AndAlso / OrElse

(EDIT: En savoir plus ici: Dois-je toujours utiliser les opérateurs AndAlso et OrElse? )

Joël Coehoorn
la source
Je n'appellerais pas cela caché du tout, si Contact IsNot Nothing AndAlso Contact.ContactId> 0 Alors faites-le, si vous allez utiliser Et vous aurez une exception levée.
Shimmy Weitzhandler le
25

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.

Joël Coehoorn
la source
1
Une utilisation de ceci est de garder un compteur qui s'incrémentera chaque fois que la méthode est appelée. Si la variable est marquée Static, elle ne sera pas réinitialisée à chaque appel de méthode; il ne sera initialisé que lors du premier appel, puis conservera sa valeur.
Ryan Lundy
C'est la raison pour laquelle les membres statiques de la classe sont nommés «partagés» dans VB.NET
Enrico Campidoglio
La statique est encore plus mauvaise dans VB.NET que dans VB classique. Les variables statiques doivent être évitées chaque fois que cela est possible.
Sam Axe
6
@Boo - c'est assez radieux. Quelle est votre justification? Je pense que les variables statiques sont utiles.
MarkJ
4
Static, utilisé comme dans les exemples ci-dessus, permet une forme unique d'encapsulation: des variables de niveau classe qui ont une portée de niveau méthode. Sans cela, vous devrez créer une variable au niveau de la classe qui serait accessible à n'importe quel membre de la classe, même si vous ne l'utilisez que dans une seule méthode.
Ryan Lundy
25

Dans vb, il y a une différence entre ces opérateurs:

/on Double
\est en Integerignorant 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
Shimmy
la source
1
J'ai appris cela à la dure en essayant de trouver une aiguille dans un million de lignes de code. division régulière par rapport à un entier. bon conseil!
Jason Irwin
23

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:

  • My.Computer : accès aux informations relatives à l'ordinateur telles que le système de fichiers, le réseau, les périphériques, les informations système, etc. Il permet d'accéder à un certain nombre de ressources très importantes, notamment My.Computer.Network, My.Computer.FileSystem et My. .Ordinateur.Imprimantes.
  • My.Application : accès aux informations relatives à l'application particulière telles que le nom, la version, le répertoire actuel, etc.
  • My.User : accès aux informations relatives à l'utilisateur authentifié actuel.
  • My.Resources : accès aux ressources utilisées par l'application résidant dans les fichiers de ressources d'une manière fortement typée.
  • My.Settings : accès aux paramètres de configuration de l'application de manière fortement typée.
splattne
la source
C'est tout simplement génial et tous les gars de vb.net devraient savoir des choses dans Mon espace de noms, c'est tellement utile.
dr. evil
Mon. * FTW :).
dr. evil
3
C'est en quelque sorte utile, mais je déteste le nom stupide. Ça me rappelle ce secretgeek.net/refactvb.asp
MarkJ
23

Événements personnalisés

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
Konrad Rudolph
la source
semble cool, mais si jamais j'en ai besoin, je pense que j'aurai fait quelque chose de mal ;-). Cela semble tout simplement contraire au principe KISS.
chrissie1
4
C'est vraiment, vraiment utile lorsque vous voulez vous assurer que chaque récepteur reçoit l'événement même si un ou plusieurs lancent une exception.
Jonathan Allen
Une autre valeur (je viens de la lire sur le site MSDN) est que si votre classe lance beaucoup d'événements, vous pouvez la forcer à utiliser une table / dictionnaire de hachage comme conteneur, plutôt que de déclarer un champ pour chaque événement. msdn.microsoft.com/en-us/library/8627sbea(VS.71).aspx
riale
Cool. Je pensais que c'était l'une des fonctionnalités qui distinguaient C # et VB.NET (comme dans l'un, mais l'autre n'a pas de syntaxe pour cela). Ravi de savoir au moins que j'avais tort à cet égard.
peSHIr
21

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.

torial
la source
11
C'est l'une de ces fonctionnalités que j'ai utilisées puis j'ai intentionnellement oublié. Cela économise quelques frappes, mais gâche la mise en évidence et la lisibilité de mon code. oubliant à nouveau bien .... MAINTENANT
STW
3
Intéressant, mais pas vraiment utile. Est-ce le genre de choses sur lesquelles l'équipe VB travaille au lieu d'ajouter des fonctionnalités manquantes comme le mot-clé yield? : P
Meta-Knight
5
Cette fonctionnalité est portée pour la compatibilité descendante de VB3 (AFAIK)
Eduardo Molteni
1
les classes qui implémentent un index à clé ont-elles une interface commune dont elles héritent? comme IKeyed de la même manière que les conteneurs indexés par entiers implémentent IENumberable?
Maslow
2
Cette fonctionnalité fonctionne également avec DataRows (c'est-à-dire dr! ID) qui est TRÈS pratique dans LINQ to DataSets.
Paul
19

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
torial
la source
Je suis sûr que vous pouvez faire quelque chose comme ça en C #. Dans VB.NET, c'est juste forcé, et en C # c'est facultatif?
Jesper Blad Jensen
5
Vous pouvez également rendre le sous privé, ce qui est un excellent moyen de masquer des éléments tels que les appels à des versions obsolètes non génériques des interfaces.
Craig Gidney
3
Cela peut être une bonne idée. L'exemple classique serait si vous voulez une méthode Public Close qui agit également comme votre implémentation Dispose pour IDisposable.
MarkJ
1
C'est également très utile si vous implémentez deux interfaces qui partagent un nom de méthode.
Eric Nicholson
J'ai vu ça et j'aurais toujours aimé ne pas l'avoir fait. Ne devrait pas être autorisé.
FastAl
17

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

Chris Haas
la source
6
Oh mon Dieu ... c'est une fonctionnalité remarquable, même si je ne pense pas que je saurais ce que cela faisait si je le lisais dans le code de quelqu'un d'autre. Si vous devez le commenter juste pour savoir ce qu'il fait, vous pourriez aussi bien avoir fait passer la variable throw away à la place.
mattmc3
7
C'est en fait un effet secondaire de l'utilisation de parenthèses - Les parenthèses créent une valeur temporaire de ce qu'il y a à l'intérieur, même s'il s'agit d'un seul élément. Cet effet m'a tué dans vb6 - Les appels de sous-marins n'ont pas pris de parens, mais moi venant de C j'ai instinctivement mis les parens. 6.0 a explosé sur plusieurs paramètres, mais pour un sous-paramètre, il a heureusement passé une valeur temporaire et REFUSÉ d'honorer mon 'byref'. Cela s'est produit environ tous les 3 ans, à peu près le temps qu'il m'a fallu pour oublier le dernier incident.
FastAl
16

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")
49%
la source
Wow, c'est super cool! J'ai vu cela lors de l'utilisation des services Web, etc., mais je ne savais pas que vous pouviez faire cela avec n'importe quelle autre méthode normale.
RichC
2
Certainement un outil très pratique lorsque vous rencontrez une méthode qui prend trop d'arguments. J'essaye de nommer chaque paramètre et de mettre le nom: = valeur sur sa propre ligne. C'est beaucoup plus intuitif et propre pour les méthodes qui prennent> 5 paramètres (ma règle d'or).
STW
Particulièrement utile pour la bureautique, où vous devez gérer des méthodes avec des dizaines d'arguments facultatifs.
MarkJ
1
Ce qui est également cool, c'est que vous pouvez mélanger les deux: commencez par spécifier les paramètres requis dans l'ordre, puis passez aux paramètres nommés pour les arguments optionnels!
RBarryYoung
15

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
torial
la source
23
Il convient de noter (uniquement parce que j'ai oublié au moins deux fois) que vous pouvez avoir une instruction Using envelopper plusieurs objets jetables. La syntaxe est "Utiliser objA comme nouvel objet, objB comme nouvel objet ..." C'est beaucoup plus propre que d'imbriquer plusieurs instructions Using.
STW
Certainement l'un de mes préférés aussi.
Sam Axe
14

Les alias d'importation sont également largement inconnus:

Import winf = System.Windows.Forms

''Later
Dim x as winf.Form
torial
la source
1
Je pense que nous avons eu la même idée.
chrissie1
3
@Boo - voici un exemple simple où les alias d'importation ne sont pas mauvais. stackoverflow.com/questions/92869/…
torial
D'accord - il y a une voie évidente pour les abus, mais quelle que soit la diatribe de @ torial, c'est une excellente fonctionnalité. Chaque fois que j'inclus System.Text.RegularExpressions, je risque d'avoir des collisions de noms avec la classe "Group" puisque c'est un nom de classe courant. L'alias vous permet d'éviter d'avoir à qualifier complètement les classes ambiguës, ce qui représente un gain de temps énorme et améliore en fait la lisibilité lorsqu'il est utilisé correctement. La fonctionnalité est excellente, mais votre exemple spécifique invite en quelque sorte au ridicule - désolé de le dire.
mattmc3
14

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

Technobabble
la source
Pourquoi voudriez-vous faire ça? Je ne peux pas imaginer un cas d'utilisation où vous avez besoin de connaître le nombre d'abonnés à un événement dans VB.
Konrad Rudolph
Dans certaines circonstances, C # lève une exception si vous déclenchez l'événement et qu'il n'y a aucun gestionnaire. VB.Net ne le fera pas. D'où la nécessité de vérifier.
Joel Coehoorn le
2
Je l'ai utilisé pour un événement d'objet métier qui a soulevé des messages d'erreur de validation pour les abonnés. Je voulais vérifier si l'événement était géré afin de savoir que les erreurs de validation étaient reçues. Sinon, j'ai demandé à l'objet métier de lancer une exception.
Technobabble
2
Une autre utilisation pratique de ce membre privé est d'obtenir la liste d'appels de l'événement. Je l'ai utilisé dans plusieurs cas pour déclencher l'événement de manière asynchrone à tous les appelants (empêche l'auditeur A de modifier l'événement avant que l'auditeur B ne le reçoive; cela empêche également l'auditeur A de retarder la livraison à l'auditeur B). Je l'ai beaucoup utilisé dans des scénarios de synchronisation de données personnalisés, ainsi que dans les API.
STW
14

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
torial
la source
Je pense que cet exemple serait meilleur si vous n'utilisiez pas "Si" comme mot clé d'exemple.
Sean Gough
4
minuterie.Démarrage et minuterie.Stop vient à l'esprit comme des exemples de bonne utilisation de cela
Pondidum
5
+1 pour l'avoir signalé avec un avertissement. Il existe plusieurs classes de framework qui nécessitent cette résolution pour être correctement résolues, telles que [Assembly]
STW
5
[Enum] est un autre bon exemple de cas où vous avez besoin des crochets pour utiliser la classe au lieu du mot-clé.
Ryan Lundy
13

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.)

Ryan Lundy
la source
3
<q>serait une bonne balise, similaire à l'utilisation en Perl / Ruby. Quoi qu'il en soit, c'est un idiome assez sympa. COMME!
Konrad Rudolph
Quelle idée géniale. Merci
Jeremy
12

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)
danlash
la source
6
Pas si vous avez Option Strict On
danlash
12

Vous pouvez avoir 2 lignes de code sur une seule ligne. Par conséquent:

Dim x As New Something : x.CallAMethod
Parsa
la source
whoa ... je pensais que ce n'était possible qu'avec la classe et l'héritage
Jason
N'oubliez pasCall (New Something).CallAMethod()
Jonathan Allen
C'est un holdever de MS-Basic sur Apple] [! Dans ma boutique, je serais tout aussi ridiculisé pour avoir utilisé Gotos: - /
FastAl
La plupart du temps, cela doit être évité, mais lorsque j'aime l'utiliser, c'est dans les déclarations de cas où les lignes sont vraiment courtes, par exemple Cas 4: x = 22
dwidel
11

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
dr. mal
la source
1
Je ne savais pas que C # allait les obtenir. Ils sont sympas, mais vous devez faire attention à ne les utiliser que là où vous êtes sûr que le code ne sera pas consommé par C # car il ne les prend pas en charge. FxCop / Code Analysis vous dira de surcharger la méthode à la place.
STW
... Je viens de trouver une excellente utilisation des paramètres facultatifs, tout en les gardant hors du code de production. J'ai rédigé un court article à ce sujet sur mon site: yoooder.com/wordpress/?p=62
STW
2
Ah, je méprise tellement ça ... Mais utile pour la bureautique
dance2die
9

La casse de titre dans VB.Net peut être obtenue par un ancien fxn VB6:

StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
torial
la source
1
c'est aussi dans la classe textinfo. Je ne sais pas dans quel espace de noms se trouve. probablement system.text
Shawn
Il vaut mieux être indépendant du langage .net et utiliser la classe Globalization TextInfo pour convertir ToTitleCase. Si votre code doit être converti en C #, vous aurez beaucoup de petits méchants qui nécessitent Microsoft.VisualBasic
Jeremy
9

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
torial
la source
C'est intéressant, mais je ne sais pas exactement où cela serait utile. myObj.Something ("abc") ressemble plus à un accès à une fonction qu'à une propriété. Je ne sais pas ce que cela vous achète.
mattmc3
Je déteste l'ambiguïté. Que devrait-il être. Une méthode ou une propriété. Certains outils de refactoring suggèrent de créer les deux dans certaines situations aussi, on dirait qu'ils ne savent même pas ...
brumScouse