Ich habe einiges über das Durchsuchen der versteckten Funktionen von C # gelernt und war überrascht, als ich für VB.NET nichts Ähnliches finden konnte.
Also, was sind einige seiner versteckten oder weniger bekannten Merkmale?
Ich habe einiges über das Durchsuchen der versteckten Funktionen von C # gelernt und war überrascht, als ich für VB.NET nichts Ähnliches finden konnte.
Also, was sind einige seiner versteckten oder weniger bekannten Merkmale?
Antworten:
Die Exception When
Klausel ist weitgehend unbekannt.
Bedenken Sie:
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
sEine der wirklich verborgenen Funktionen von VB ist das completionlist
XML-Dokumentations-Tag, mit dem eigene Enum
Typen mit erweiterten Funktionen erstellt werden können. Diese Funktion funktioniert jedoch nicht in C #.
Ein Beispiel aus einem meiner jüngsten Codes:
'
''' <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
Wenn Sie einer als deklarierten Variablen einen Wert zuweisen Rule
, bietet die IDE eine IntelliSense-Liste möglicher Werte aus RuleTemplates
.
Da dies eine Funktion ist, die auf der IDE basiert, ist es schwierig zu zeigen, wie dies aussieht, wenn Sie es verwenden, aber ich verwende nur einen Screenshot:
Abschlussliste in Aktion http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
Tatsächlich ist IntelliSense zu 100% identisch mit dem, was Sie bei der Verwendung von erhalten Enum
.
friend
oder dieselbe Klasse wie die Aufzählung verwenden: Rule
anstelle von RuleTemplate
.
Haben Sie den Vergleichsoperator "Gefällt mir" bemerkt?
Dim b As Boolean = "file.txt" Like "*.txt"
Mehr von 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 kennt eine primitive Art von typedef
Via- Import
Aliasen:
Imports S = System.String
Dim x As S = "Hello"
Dies ist nützlicher, wenn es in Verbindung mit generischen Typen verwendet wird:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
es sollte sein. ;-) Irgendwie ist dieser Fehler seit fast einem Jahr unentdeckt geblieben (und hat 28 positive Stimmen erhalten).
Imports Assert = xUnit.Assert
Oh! und vergessen Sie nicht XML-Literale .
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
(Ich fand dies besonders praktisch, wenn ich Tests zum Parsen von CSV-Dateien schrieb, bei denen jedes Feld in Anführungszeichen stand. Es hätte keinen Spaß gemacht, all diese Anführungszeichen von Hand in meinem zu entkommen Testlinien.)
Die Objektinitialisierung ist auch da!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
ist ein Wunder. An der Oberfläche funktioniert es ähnlich wie der CType
Operator, indem es ein Objekt von einem Typ in einen anderen konvertiert. Es funktioniert jedoch nach einem viel strengeren Regelwerk. CType
Das tatsächliche Verhalten ist daher oft undurchsichtig und es ist überhaupt nicht ersichtlich, welche Art von Konvertierung ausgeführt wird.
DirectCast
unterstützt nur zwei verschiedene Operationen:
Jede andere Umwandlung funktioniert nicht (z. B. der Versuch, ein Integer
bis a zu entpacken Double
) und führt zu einem Kompilierungs- / Laufzeitfehler (abhängig von der Situation und dem, was durch statische Typprüfung erkannt werden kann). Ich verwende daher DirectCast
nach Möglichkeit, da dies meine Absicht am besten erfasst: Je nach Situation möchte ich entweder einen Wert bekannten Typs entpacken oder einen Upcast durchführen. Ende der Geschichte.
Unter Verwendung CType
, auf der anderen Seite, läßt den Leser des Codes fragen , was wirklich der Programmierer gedacht , weil es für alle Arten von verschiedenen Operationen löst, benutzerdefinierten Code einschließlich Aufruf.
Warum ist das eine versteckte Funktion? Das VB-Team hat eine Richtlinie 1 veröffentlicht , die von der Verwendung DirectCast
(obwohl sie tatsächlich schneller ist!) Abrät, um den Code einheitlicher zu gestalten. Ich behaupte, dass dies eine schlechte Richtlinie ist, die umgekehrt werden sollte: Wenn immer möglich, bevorzugen DirectCast
Sie den allgemeineren CType
Operator. Es macht den Code viel klarer. CType
sollte dagegen nur aufgerufen werden, wenn dies tatsächlich beabsichtigt ist, dh wenn ein sich verengender CType
Operator (vgl. Operatorüberladung ) aufgerufen werden soll.
1) Ich kann keinen Link zu der Richtlinie finden, aber ich habe Paul Vicks Einstellung dazu gefunden (Chefentwickler des VB-Teams):
In der realen Welt werden Sie den Unterschied kaum bemerken, daher können Sie sich auch für flexiblere Konvertierungsoperatoren wie CType, CInt usw. entscheiden.
(EDIT von Zack: Erfahren Sie hier mehr: Wie soll ich in VB.NET umwandeln? )
TryCast
da ich hauptsächlich einen Knochen hatte, den ich mit dem allgegenwärtigen Gebrauch von pflücken konnte CType
.
TryCast
gemäß der Dokumentation nur für Referenztypen funktionieren.
If
Bedingter und KoaleszenzoperatorIch weiß nicht, wie versteckt Sie es nennen würden, aber die Funktion Iif ([Ausdruck], [Wert, wenn wahr], [Wert, wenn falsch]) als Objekt könnte zählen.
Es ist weniger versteckt als veraltet ! VB 9 hat den If
Operator, der viel besser ist und genau wie der Bedingungs- und Koaleszenzoperator von C # funktioniert (je nachdem, was Sie wollen):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Bearbeitet, um ein weiteres Beispiel zu zeigen:
Dies funktioniert mit If()
, verursacht aber eine Ausnahme mitIIf()
Dim x = If(b<>0,a/b,0)
:?
Operator von C und Perl , es ist nicht nur eine vereinfachte Version.
Das ist schön. Die Select Case-Anweisung in VB.Net ist sehr leistungsfähig.
Klar gibt es den Standard
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Aber es gibt noch mehr ...
Sie können Bereiche ausführen:
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
Und noch mehr...
Sie können (obwohl dies möglicherweise keine gute Idee ist) mehrere Variablen boolesch prüfen:
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
ist, dass es so aussieht, als würde es jede der Case
Anweisungen auswerten und den Code für jede wahr ausführen, was wahr ist. Tatsächlich wertet es sie jedoch einzeln aus und führt nur den Code für den ersten aus , der wahr ist. Die Syntax für If
ist in dieser Hinsicht viel klarer ( If...Else If...Else If...Else
).
Eine wichtige Zeitersparnis, die ich ständig verwende, ist das Schlüsselwort With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
Ich schreibe einfach nicht mehr als ich muss!
Der beste und einfachste CSV-Parser:
Microsoft.VisualBasic.FileIO.TextFieldParser
Durch Hinzufügen eines Verweises auf Microsoft.VisualBasic kann dieser in jeder anderen .NET-Sprache verwendet werden, z. B. C #
(BEARBEITEN: Weitere Informationen finden Sie hier: Soll ich immer die Operatoren AndAlso und OrElse verwenden? )
Statische Elemente in Methoden.
Beispielsweise:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
In der obigen Funktion wird der reguläre Musterausdruck immer nur einmal erstellt, unabhängig davon, wie oft die Funktion aufgerufen wird.
Eine andere Verwendung besteht darin, eine Instanz von "zufällig" zu behalten:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Dies ist auch nicht dasselbe, als es einfach als gemeinsames Mitglied der Klasse zu deklarieren. Artikel, die auf diese Weise deklariert wurden, sind garantiert auch threadsicher. In diesem Szenario spielt es keine Rolle, da sich der Ausdruck niemals ändern wird, aber es gibt andere, bei denen dies der Fall sein könnte.
In vb gibt es einen Unterschied zwischen diesen Operatoren:
/
wird Double
\
sich Integer
der Rest ignoriert
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
Der in Visual Basic 2005 eingeführte Namespace "My" gefällt mir sehr gut . My ist eine Verknüpfung zu mehreren Gruppen von Informationen und Funktionen. Es bietet schnellen und intuitiven Zugriff auf die folgenden Arten von Informationen:
Obwohl selten nützlich, kann die Ereignisbehandlung stark angepasst werden:
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
Dies kann dann folgendermaßen getestet werden:
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
Ich habe gerade einen Artikel über das "!" Operator, auch als "Dictionary Lookup Operator" bekannt. Hier ist ein Auszug aus dem Artikel unter: http://panopticoncentral.net/articles/902.aspx
Der technische Name für die! operator ist der "Dictionary Lookup Operator". Ein Wörterbuch ist ein beliebiger Sammlungstyp, der eher durch einen Schlüssel als durch eine Zahl indiziert wird, genau wie die Einträge in einem englischen Wörterbuch durch das Wort indiziert werden, dessen Definition Sie möchten. Das häufigste Beispiel für einen Wörterbuchtyp ist System.Collections.Hashtable, mit dem Sie der Hashtabelle (Schlüssel-, Wert-) Paare hinzufügen und dann mithilfe der Schlüssel Werte abrufen können. Mit dem folgenden Code werden beispielsweise drei Einträge zu einer Hashtabelle hinzugefügt und einer davon mit dem Schlüssel "Schweinefleisch" nachgeschlagen.
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
Das ! Mit dem Operator können Werte aus jedem Wörterbuchtyp gesucht werden, der seine Werte mithilfe von Zeichenfolgen indiziert. Die Kennung nach dem! wird als Schlüssel für die Suchoperation verwendet. Der obige Code hätte also stattdessen geschrieben werden können:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
Das zweite Beispiel ist völlig gleichbedeutend mit dem ersten, sieht aber zumindest für meine Augen viel schöner aus. Ich finde, dass es viele Orte gibt, an denen! kann verwendet werden, insbesondere wenn es um XML und das Web geht, wo es nur Tonnen von Sammlungen gibt, die durch Zeichenfolgen indiziert sind. Eine unglückliche Einschränkung ist, dass die Sache nach dem! muss immer noch ein gültiger Bezeichner sein. Wenn die Zeichenfolge, die Sie als Schlüssel verwenden möchten, ein ungültiges Bezeichnerzeichen enthält, können Sie das! Operator. (Sie können beispielsweise nicht "Tabelle! AB $ CD = 5" sagen, da $ in Bezeichnern nicht zulässig ist.) In VB6 und früheren Versionen können Sie Klammern verwenden, um ungültige Bezeichner zu umgehen (z. B. "Tabelle! [AB $") CD] "), aber als wir anfingen, Klammern zu verwenden, um Schlüsselwörter zu umgehen, haben wir die Fähigkeit dazu verloren. In den meisten Fällen,
Um wirklich technisch zu werden, funktioniert x! Y, wenn x eine Standardeigenschaft hat, die einen String oder ein Objekt als Parameter verwendet. In diesem Fall wird x! Y in x.DefaultProperty ("y") geändert. Eine interessante Randnotiz ist, dass es in der lexikalischen Grammatik der Sprache eine spezielle Regel gibt, damit dies alles funktioniert. Das ! Zeichen wird auch als Typzeichen in der Sprache verwendet, und Typzeichen werden vor Operatoren gegessen. Ohne eine spezielle Regel würde x! Y als "x! Y" anstelle von "x! Y" gescannt. Glücklicherweise haben wir, da es in der Sprache keinen Ort gibt, an dem zwei Bezeichner hintereinander gültig sind, die Regel eingeführt, dass, wenn das nächste Zeichen nach dem! ist der Beginn eines Bezeichners, wir betrachten das! ein Operator und kein Typzeichen sein.
Dies ist eingebaut und ein klarer Vorteil gegenüber C #. Die Möglichkeit, eine Schnittstellenmethode zu implementieren, ohne denselben Namen verwenden zu müssen.
Sowie:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
ByVal erzwingen
Wenn Sie in VB Ihre Argumente in zusätzliche Klammern setzen, können Sie die ByRef-Deklaration der Methode überschreiben und in ein ByVal umwandeln. Der folgende Code erzeugt beispielsweise 4, 5, 5 anstelle von 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
Siehe Argument, das nicht durch Prozeduraufruf - zugrunde liegende Variable geändert wird
Übergeben von Parametern nach Namen und, um sie neu zu ordnen
Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)
'Do stuff
End function
Verwendung:
Module Module1
Sub Main()
MyFunc() 'No params specified
End Sub
End Module
Kann auch mit der Parameterspezifikation ": =" in beliebiger Reihenfolge aufgerufen werden:
MyFunc(displayOrder:=10, msg:="mystring")
Die Using-Anweisung ist ab VB 8 neu, C # hatte sie von Anfang an. Es ruft die automatische Entsorgung für Sie auf.
Z.B
Using lockThis as New MyLocker(objToLock)
End Using
Import-Aliase sind ebenfalls weitgehend unbekannt:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Beachten Sie die folgende Ereignisdeklaration
Public Event SomethingHappened As EventHandler
In C # können Sie mithilfe der folgenden Syntax nach Ereignisabonnenten suchen:
if(SomethingHappened != null)
{
...
}
Der VB.NET-Compiler unterstützt dies jedoch nicht. Es wird tatsächlich ein verstecktes privates Mitgliedsfeld erstellt, das in IntelliSense nicht sichtbar ist:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Mehr Informationen:
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
Wenn Sie einen Variablennamen benötigen, der mit dem eines Schlüsselworts übereinstimmt, schließen Sie ihn in Klammern ein. Nicht notwendig. Die beste Vorgehensweise - aber sie kann mit Bedacht eingesetzt werden.
z.B
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
zB Beispiel aus Kommentaren (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Es gibt einige Antworten zu XML-Literalen, jedoch nicht zu diesem speziellen Fall:
Sie können XML-Literale verwenden, um Zeichenfolgenliterale einzuschließen, die sonst maskiert werden müssten. String-Literale, die beispielsweise doppelte Anführungszeichen enthalten.
An Stelle von:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Du kannst das:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Dies ist besonders nützlich, wenn Sie ein Literal für die CSV-Analyse testen:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(Sie müssen das <string>
Tag natürlich nicht verwenden; Sie können jedes beliebige Tag verwenden.)
<q>
wäre ein gutes Tag, ähnlich der Verwendung in Perl / Ruby. Wie auch immer, das ist eine nette Redewendung. MÖGEN!
DateTime kann initialisiert werden, indem Sie Ihr Datum mit # umgeben
Dim independanceDay As DateTime = #7/4/1776#
Sie können zusammen mit dieser Syntax auch die Typinferenz verwenden
Dim independanceDay = #7/4/1776#
Das ist viel schöner als die Verwendung des Konstruktors
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Sie können 2 Codezeilen in nur einer Zeile haben. daher:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Optionale Parameter
Optionale Optionen sind so viel einfacher als das Erstellen neuer Überladungen, wie z.
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
Title Case in VB.Net kann mit einem alten VB6 fxn erreicht werden:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Eigenschaften mit Parametern
Ich habe einige C # -Programmierungen durchgeführt und eine Funktion entdeckt, die VB.Net fehlte, aber hier nicht erwähnt wurde.
Ein Beispiel dafür (sowie die c # -Einschränkung) finden Sie unter: Verwenden der typischen get set-Eigenschaften in C # ... mit Parametern
Ich habe den Code aus dieser Antwort extrahiert:
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