Aprendí bastante navegando por las características ocultas de C # y me sorprendió cuando no pude encontrar algo similar para VB.NET.
¿Cuáles son algunas de sus características ocultas o menos conocidas?
Aprendí bastante navegando por las características ocultas de C # y me sorprendió cuando no pude encontrar algo similar para VB.NET.
¿Cuáles son algunas de sus características ocultas o menos conocidas?
Respuestas:
La Exception When
cláusula es en gran parte desconocida.
Considera esto:
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 de las características ocultas reales de VB es la completionlist
etiqueta de documentación XML que se puede usar para crear Enum
tipos propios con funcionalidad extendida. Sin embargo, esta característica no funciona en C #.
Un ejemplo de un código mío reciente:
'
''' <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
Ahora, al asignar un valor a una variable declarada como Rule
, el IDE ofrece una lista IntelliSense de posibles valores de RuleTemplates
.
Dado que esta es una característica que depende del IDE, es difícil mostrar cómo se ve esto cuando la usa, pero solo usaré una captura de pantalla:
Lista de finalización en acción http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png
De hecho, IntelliSense es 100% idéntico a lo que obtienes cuando usas un Enum
.
friend
o usando la misma clase que la enumeración: en Rule
lugar de RuleTemplate
.
¿Has notado el operador de comparación Me gusta?
Dim b As Boolean = "file.txt" Like "*.txt"
Más de 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 conoce un tipo primitivo de alias typedef
vía Import
:
Imports S = System.String
Dim x As S = "Hello"
Esto es más útil cuando se usa junto con tipos genéricos:
Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Imports
debería ser. ;-) De alguna manera, este error no se detectó (y obtuvo 28 votos a favor) durante casi todo un año.
Imports Assert = xUnit.Assert
Oh! y no te olvides de XML Literals .
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
(He encontrado esta especialmente útil al escribir pruebas en analizar archivos CSV en el que cada campo se comillas Sería. No diversión haber sido de escapar de todas estas citas de la mano en mi líneas de prueba.)
¡La inicialización de objetos también está ahí!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
DirectCast
DirectCast
es una maravilla En la superficie, funciona de manera similar al CType
operador en que convierte un objeto de un tipo a otro. Sin embargo, funciona con un conjunto de reglas mucho más estricto. CType
Por lo tanto, el comportamiento real suele ser opaco y no es del todo evidente qué tipo de conversión se ejecuta.
DirectCast
solo admite dos operaciones distintas:
Cualquier otra conversión no funcionará (por ejemplo, tratar de descomprimir un Integer
a a Double
) y generará un error de tiempo de compilación / tiempo de ejecución (dependiendo de la situación y de lo que se puede detectar mediante la verificación de tipo estático). Por lo tanto, lo uso DirectCast
siempre que sea posible, ya que esto captura mi mejor intención: dependiendo de la situación, quiero desempaquetar un valor de tipo conocido o realizar una transmisión. Fin de la historia.
El uso CType
, por otro lado, deja al lector del código preguntándose qué pretendía realmente el programador porque resuelve todo tipo de operaciones diferentes, incluida la llamada de código definido por el usuario.
¿Por qué es esta una característica oculta? El equipo de VB ha publicado una directriz 1 que desalienta el uso de DirectCast
(¡aunque en realidad es más rápido!) Para que el código sea más uniforme. Sostengo que esta es una mala guía que debería revertirse: siempre que sea posible, favorezca DirectCast
al CType
operador más general . Hace que el código sea mucho más claro. CType
, por otro lado, solo se debe invocar si esto realmente se pretende, es decir, cuando se debe llamar a un CType
operador de estrechamiento (cf. sobrecarga del operador ).
1) No puedo encontrar un enlace a la directriz, pero he encontrado la opinión de Paul Vick (desarrollador principal del equipo VB):
En el mundo real, casi nunca notará la diferencia, por lo que podría optar por los operadores de conversión más flexibles como CType, CInt, etc.
(EDITAR por Zack: Obtenga más información aquí: ¿Cómo debo transmitir en VB.NET? )
TryCast
ese entonces, ya que principalmente tenía un hueso para elegir con el uso generalizado CType
.
TryCast
solo funcionan en tipos de referencia, según la documentación.
If
operador condicional y de fusiónNo sé qué tan oculto lo llamarías, pero la función Iif ([expresión], [valor si es verdadero], [valor si es falso]) como objeto podría contar.
¡No está tan escondido como en desuso ! VB 9 tiene el If
operador que es mucho mejor y funciona exactamente como el operador condicional y de fusión de C # (según lo que desee):
Dim x = If(a = b, c, d)
Dim hello As String = Nothing
Dim y = If(hello, "World")
Editado para mostrar otro ejemplo:
Esto funcionará con If()
, pero causará una excepción conIIf()
Dim x = If(b<>0,a/b,0)
:?
operador de C y Perl , no es solo una versión simplificada.
Esta es buena. La declaración de Seleccionar caso dentro de VB.Net es muy poderosa.
Claro que existe el estándar
Select Case Role
Case "Admin"
''//Do X
Case "Tester"
''//Do Y
Case "Developer"
''//Do Z
Case Else
''//Exception case
End Select
Pero hay más ...
Puedes hacer rangos:
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
Y aún más ...
Puede (aunque puede no ser una buena idea) realizar comprobaciones booleanas en múltiples 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
es que parece que evalúa cada una de las Case
declaraciones y ejecuta el código para cada una de ellas, lo cual es cierto. Pero, de hecho, los evalúa uno por uno y solo ejecuta el código para el primero, lo cual es cierto. La sintaxis para If
es mucho más clara a este respecto ( If...Else If...Else If...Else
).
Un gran ahorro de tiempo que uso todo el tiempo es la palabra clave With :
With ReallyLongClassName
.Property1 = Value1
.Property2 = Value2
...
End With
¡Simplemente no me gusta escribir más de lo necesario!
El mejor y más fácil analizador CSV:
Microsoft.VisualBasic.FileIO.TextFieldParser
Al agregar una referencia a Microsoft.VisualBasic, esto se puede usar en cualquier otro lenguaje .Net, por ejemplo, C #
(EDITAR: Obtenga más información aquí: ¿Debería usar siempre los operadores AndAlso y OrElse? )
Miembros estáticos en métodos.
Por ejemplo:
Function CleanString(byval input As String) As String
Static pattern As New RegEx("...")
return pattern.Replace(input, "")
End Function
En la función anterior, la expresión regular de patrón solo se creará una vez, sin importar cuántas veces se llame a la función.
Otro uso es mantener una instancia de "aleatorio" alrededor:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Además, esto no es lo mismo que declararlo simplemente como un miembro compartido de la clase; los artículos declarados de esta manera también están garantizados para ser seguros para subprocesos. No importa en este escenario ya que la expresión nunca cambiará, pero hay otras en las que podría cambiar.
En vb hay una diferencia entre estos operadores:
/
se Double
\
está Integer
ignorando el 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
Realmente me gusta el espacio de nombres "Mi" que se introdujo en Visual Basic 2005. Mi es un acceso directo a varios grupos de información y funcionalidad. Proporciona acceso rápido e intuitivo a los siguientes tipos de información:
Aunque rara vez es útil, el manejo de eventos se puede personalizar en gran medida:
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
Esto se puede probar de la siguiente manera:
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
Acabo de encontrar un artículo que habla sobre el "!" operador, también conocido como el "operador de búsqueda de diccionario". Aquí hay un extracto del artículo en: http://panopticoncentral.net/articles/902.aspx
El nombre técnico para el! operador es el "operador de búsqueda de diccionario". Un diccionario es cualquier tipo de colección que está indexada por una clave en lugar de un número, al igual que la forma en que las entradas en un diccionario de inglés están indexadas por la palabra de la que desea la definición. El ejemplo más común de un tipo de diccionario es System.Collections.Hashtable, que le permite agregar pares (clave, valor) en la tabla hash y luego recuperar valores utilizando las claves. Por ejemplo, el siguiente código agrega tres entradas a una tabla hash y busca una de ellas con la tecla "Pork".
Dim Table As Hashtable = New Hashtable
Table("Orange") = "A fruit"
Table("Broccoli") = "A vegetable"
Table("Pork") = "A meat"
Console.WriteLine(Table("Pork"))
Los ! El operador se puede utilizar para buscar valores de cualquier tipo de diccionario que indexe sus valores mediante cadenas. El identificador después de! se utiliza como clave en la operación de búsqueda. Entonces, el código anterior podría haberse escrito:
Dim Table As Hashtable = New Hashtable
Table!Orange = "A fruit"
Table!Broccoli = "A vegetable"
Table!Pork = "A meat"
Console.WriteLine(Table!Pork)
El segundo ejemplo es completamente equivalente al primero, pero se ve mucho mejor, al menos a mis ojos. Me parece que hay muchos lugares donde! se puede usar, especialmente cuando se trata de XML y la web, donde solo hay toneladas de colecciones indexadas por cadena. Una limitación desafortunada es que lo que sigue al! aún tiene que ser un identificador válido, por lo que si la cadena que desea usar como clave tiene algún carácter identificador no válido, ¡no puede usar el! operador. (No puede, por ejemplo, decir "Tabla! AB $ CD = 5" porque $ no es legal en los identificadores). En VB6 y anteriores, puede usar corchetes para escapar de identificadores no válidos (es decir, "Tabla! [AB $ CD] "), pero cuando comenzamos a usar corchetes para escapar de las palabras clave, perdimos la capacidad de hacerlo. En la mayoría de los casos,
Para ser realmente técnico, x! Y funciona si x tiene una propiedad predeterminada que toma una Cadena u Objeto como parámetro. En ese caso, x! Y se cambia a x.DefaultProperty ("y"). Una nota al margen interesante es que hay una regla especial en la gramática léxica del lenguaje para hacer que todo funcione. Los ! el carácter también se usa como carácter de tipo en el idioma, y los caracteres de tipo se comen antes que los operadores. Entonces, sin una regla especial, x! Y se escanearía como "x! Y" en lugar de "x! Y". Afortunadamente, dado que no hay lugar en el idioma donde dos identificadores en una fila son válidos, acabamos de introducir la regla de que si el siguiente carácter después de! es el comienzo de un identificador, consideramos el! ser un operador y no un tipo de letra.
Esto está integrado y es una ventaja definitiva sobre C #. La capacidad de implementar un método de interfaz sin tener que usar el mismo nombre.
Como:
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo
End Sub
Forzando ByVal
En VB, si ajusta sus argumentos en un conjunto adicional de paréntesis, puede anular la declaración ByRef del método y convertirlo en ByVal. Por ejemplo, el siguiente código produce 4, 5, 5 en lugar 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
Consulte Argumento no modificado por llamada de procedimiento - Variable subyacente
Pasar parámetros por nombre y, por lo tanto, reordenarlos
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
También se puede llamar utilizando la especificación del parámetro ": =" en cualquier orden:
MyFunc(displayOrder:=10, msg:="mystring")
La instrucción Using es nueva a partir de VB 8, C # la tuvo desde el principio. Llama a disponer automáticamente para usted.
P.ej
Using lockThis as New MyLocker(objToLock)
End Using
Los alias de importación también son en gran medida desconocidos:
Import winf = System.Windows.Forms
''Later
Dim x as winf.Form
Considere la siguiente declaración de evento
Public Event SomethingHappened As EventHandler
En C #, puede verificar si hay suscriptores de eventos utilizando la siguiente sintaxis:
if(SomethingHappened != null)
{
...
}
Sin embargo, el compilador VB.NET no es compatible con esto. Realmente crea un campo de miembro privado oculto que no es visible en IntelliSense:
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If
Más información:
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 necesita un nombre de variable que coincida con el de una palabra clave, escríbalo entre corchetes. No nec. Sin embargo, es la mejor práctica, pero se puede usar sabiamente.
p.ej
Class CodeException
Public [Error] as String
''...
End Class
''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
Ejemplo de comentarios (@Pondidum):
Class Timer
Public Sub Start()
''...
End Sub
Public Sub [Stop]()
''...
End Sub
Hay un par de respuestas sobre XML Literals, pero no sobre este caso específico:
Puede usar XML Literals para encerrar literales de cadena que de lo contrario tendrían que escapar. Literales de cadena que contienen comillas dobles, por ejemplo.
En lugar de esto:
Dim myString = _
"This string contains ""quotes"" and they're ugly."
Puedes hacerlo:
Dim myString = _
<string>This string contains "quotes" and they're nice.</string>.Value
Esto es especialmente útil si está probando un literal para el análisis CSV:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(No tiene que usar la <string>
etiqueta, por supuesto; puede usar cualquier etiqueta que desee).
<q>
sería una buena etiqueta, similar al uso en Perl / Ruby. De todos modos, es un buen lenguaje. ¡ME GUSTA!
DateTime se puede inicializar rodeando su fecha con #
Dim independanceDay As DateTime = #7/4/1776#
También puede usar la inferencia de tipos junto con esta sintaxis
Dim independanceDay = #7/4/1776#
Eso es mucho mejor que usar el constructor
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
Puede tener 2 líneas de código en una sola línea. por lo tanto:
Dim x As New Something : x.CallAMethod
Call (New Something).CallAMethod()
Parámetros opcionales
Los opcionales son mucho más fáciles que crear una nueva sobrecarga, como:
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''//do stuff
End Function
El título de caso en VB.Net se puede lograr con un viejo VB6 fxn:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Propiedades con parámetros
He estado haciendo programación en C # y descubrí una característica que faltaba en VB.Net, pero que no se mencionó aquí.
Puede ver un ejemplo de cómo hacer esto (así como la limitación de c #) en: Uso de las propiedades típicas de obtención de conjunto en C # ... con parámetros
He extraído el código de esa respuesta:
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