Características ocultas de VB.NET?
hidden-features (30)
He aprendido bastante a navegar a través de Hidden Features of 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?
Custom Enum
s
Una de las características ocultas reales de VB es la etiqueta de documentación XML de la lista de completionlist
que se puede usar para crear tipos propios de tipo Enum
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
.
/EDITAR:
Como esta es una función que depende del IDE, es difícil mostrar cómo se ve cuando la usas, 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, el IntelliSense es 100% idéntico al que obtienes cuando usas un Enum
.
Eventos personalizados
Aunque rara vez es útil, el manejo de eventos puede ser muy personalizado:
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
Typedefs
VB conoce un tipo primitivo de typedef
mediante Import
alias:
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)
DirectCast
DirectCast
es una maravilla. En la superficie, funciona de manera similar al operador de CType
porque convierte un objeto de un tipo en otro. Sin embargo, funciona con un conjunto de reglas mucho más estrictas. El comportamiento real de CType
es por lo tanto a menudo opaco y no es del todo evidente qué tipo de conversión se ejecuta.
DirectCast
solo admite dos operaciones distintas:
- Unboxing de un tipo de valor, y
- upcasting en la jerarquía de clases.
Cualquier otro elenco no funcionará (por ejemplo, intentar desvincular un Integer
a un Double
) y dará como resultado un error de tiempo de compilación / tiempo de ejecución (dependiendo de la situación y de lo que pueda detectarse mediante la comprobación del tipo estático). Por lo tanto, uso DirectCast
siempre que sea posible, ya que esto capta mejor mi intención: dependiendo de la situación, quiero desempaquetar un valor de tipo conocido o realizar un upcast. Fin de la historia.
El uso de CType
, por otro lado, deja al lector del código preguntándose qué pretendía realmente el programador porque se resuelve con todo tipo de operaciones diferentes, incluido el llamado al código definido por el usuario.
¿Por qué es esta una característica oculta? El equipo de VB ha publicado una guía 1 que desalienta el uso de DirectCast
(¡aunque es más rápido!) Para hacer que el código sea más uniforme. Argumento que esta es una mala directriz que debe revertirse: siempre que sea posible, favor de DirectCast
sobre el operador general de CType
. Hace el código mucho más claro. CType
, por otro lado, solo debe llamarse si esto está realmente previsto, es decir, cuando se debe llamar a un operador de CType
estrecha (véase la sobrecarga del operador ).
1) No puedo encontrar un enlace a la guía pero he encontrado la opinión de Paul Vick (desarrollador principal del equipo de VB):
En el mundo real, casi nunca notará la diferencia, por lo que es mejor que vaya con los operadores de conversión más flexibles como CType, CInt, etc.
(EDIT por Zack: aprende más aquí: ¿cómo debo lanzar en VB.NET? )
If
operador es condicional y se une
No sé qué tan oculto lo llamarías, pero el Iif ([expresión], [valor si es verdadero], [valor si es falso]) Como función de objeto podría contar.
¡No está tan escondido como desaprobado ! VB 9 tiene el operador If
que es mucho mejor y funciona exactamente como el operador condicional y coalescente de C # (dependiendo de 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 causa una excepción con IIf()
Dim x = If(b<>0,a/b,0)
¿Has notado el operador de comparación Like?
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*"
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 del diccionario". Un diccionario es cualquier tipo de colección indexada por una clave en lugar de un número, al igual que la forma en que las entradas de un diccionario de inglés están indexadas por la palabra que desea definir. 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 con las teclas. Por ejemplo, el siguiente código agrega tres entradas a una tabla hash, y busca una de ellas usando la tecla "Cerdo".
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 usar para buscar valores de cualquier tipo de diccionario que indexe sus valores mediante cadenas. El identificador después de! se usa como la clave en la operación de búsqueda. Entonces, el código anterior podría haber sido 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 para mí. ¡Encuentro 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 cadenas. ¡Una desafortunada limitación es que lo que sigue a la! todavía tiene que ser un identificador válido, por lo que si la cadena que desea utilizar como clave tiene algún carácter identificador no válido, ¡no puede usar! operador. (No puede, por ejemplo, decir "Table! AB $ CD = 5" porque $ no es legal en los identificadores). En VB6 y anteriores, podría usar corchetes para escapar de los identificadores no válidos (es decir, "Table! [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, sin embargo, esto no es una limitación excesiva.
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 que todo esto funcione. Los ! el carácter también se usa como un carácter de tipo en el idioma, y los caracteres de tipo se comen antes de 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 en el que dos identificadores en una fila son válidos, ¡simplemente presentamos la regla de que si el siguiente personaje después de! es el inicio de un identificador, consideramos el! ser un operador y no un personaje de tipo.
El mejor y más fácil analizador de CSV:
Microsoft.VisualBasic.FileIO.TextFieldParser
Al agregar una referencia a Microsoft.VisualBasic, esto se puede usar en cualquier otro lenguaje .Net, por ejemplo, C #
En vb hay una diferencia entre estos operadores:
/
es Double
/
es 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
Esta es una linda. La sentencia Select Case dentro de VB.Net es muy poderosa.
Seguro 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 ...
Puedes (aunque puede que no sea una buena idea) hacer controles booleanos 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
Esto está incorporado, y 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
La inicialización de objetos también está allí.
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
Me gusta mucho el espacio de nombres "Mi" que se presentó 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:
- My.Computer : acceso a la información relacionada con la computadora, como sistema de archivos, red, dispositivos, información del sistema, etc. Proporciona acceso a una serie de recursos muy importantes, incluidos My.Computer.Network, My.Computer.FileSystem y My. .Computadora.Impresoras.
- My.Application : acceso a información relacionada con la aplicación en particular, como nombre, versión, directorio actual, etc.
- My.User : acceso a la información relacionada con el usuario autenticado actual.
- My.Resources : acceso a los recursos utilizados por la aplicación que reside en los archivos de recursos de una manera fuertemente tipada.
- My.Settings : accede a la configuración de la aplicación de una manera fuertemente tipada.
Oh! y no olvide XML Literals .
Dim contact2 = _
<contact>
<name>Patrick Hines</name>
<%= From p In phoneNumbers2 _
Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
%>
</contact>
Un importante 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!
Forzar 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 vez 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
Ver argumento que no se ha modificado mediante llamada de procedimiento - Variable subyacente
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 de:
Function GetNextRandom() As Integer
Static r As New Random(getSeed())
Return r.Next()
End Function
Además, esto no es lo mismo que simplemente declararlo como miembro Compartido de la clase; los artículos declarados de esta manera también garantizan la seguridad de los subprocesos. No importa en este escenario ya que la expresión nunca cambiará, pero hay otras donde podría.
Optional Parameters
Optionals are so much easier than creating a new overloads, such as :
Function CloseTheSystem(Optional ByVal msg AS String = "Shutting down the system...")
Console.Writeline(msg)
''''//do stuff
End Function
Properties with parameters
I have been doing some C# programming, and discovered a feature that was missing that VB.Net had, but was not mentioned here.
An example of how to do this (as well as the c# limitation) can be seen at: Using the typical get set properties in C#... with parameters
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
Consider the following event declaration
Public Event SomethingHappened As EventHandler
In C#, you can check for event subscribers by using the following syntax:
if(SomethingHappened != null)
{
...
}
However, the VB.NET compiler does not support this. It actually creates a hidden private member field which is not visible in 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
DateTime can be initialized by surrounding your date with #
Dim independanceDay As DateTime = #7/4/1776#
You can also use type inference along with this syntax
Dim independanceDay = #7/4/1776#
That''s a lot nicer than using the constructor
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)
If you need a variable name to match that of a keyword, enclose it with brackets. Not nec. the best practice though - but it can be used wisely.
p.ej
Class CodeException
Public [Error] as String
''''...
End Class
''''later
Dim e as new CodeException
e.Error = "Invalid Syntax"
eg Example from comments(@Pondidum):
Class Timer
Public Sub Start()
''''...
End Sub
Public Sub [Stop]()
''''...
End Sub
Import aliases are also largely unknown:
Import winf = System.Windows.Forms
''''Later
Dim x as winf.Form
La cláusula Exception When
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
Passing parameters by name and, so reordering them
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
Can also be called using the ":=" parameter specification in any order:
MyFunc(displayOrder:=10, msg:="mystring")
The Using statement is new as of VB 8, C# had it from the start. It calls dispose automagically for you.
P.ej
Using lockThis as New MyLocker(objToLock)
End Using
There are a couple of answers about XML Literals, but not about this specific case:
You can use XML Literals to enclose string literals that would otherwise need to be escaped. String literals that contain double-quotes, for instance.
En lugar de esto:
Dim myString = _
"This string contains ""quotes"" and they''re ugly."
You can do this:
Dim myString = _
<string>This string contains "quotes" and they''re nice.</string>.Value
This is especially useful if you''re testing a literal for CSV parsing:
Dim csvTestYuck = _
"""Smith"", ""Bob"", ""123 Anywhere St"", ""Los Angeles"", ""CA"""
Dim csvTestMuchBetter = _
<string>"Smith", "Bob", "123 Anywhere St", "Los Angeles", "CA"</string>.Value
(You don''t have to use the <string>
tag, of course; you can use any tag you like.)
Title Case in VB.Net can be achieved by an old VB6 fxn:
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''''0 is localeID
You can have 2 lines of code in just one line. hence:
Dim x As New Something : x.CallAMethod
- Y también operadores lógicos
(EDITAR: Obtenga más información aquí: ¿Debería usar siempre los operadores AndAlso y OrElse? )