¿Características ocultas de VB.NET?

121

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?

Sean Gough
fuente

Respuestas:

128

La Exception Whenclá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
torial
fuente
9
útil si desea capturar una SQLException específica, diga -2 que si recuerdo correctamente es el tiempo de espera de la red: Capture ex como sqlException donde ex.code = -2
Pondidum
¡Guauu! Acabo de leer esto y lo usé de inmediato para simplificar un bloque try / catch que acabo de escribir la semana pasada. Nunca supe que esto existía.
John M Gant
1
+1 Y aquí es donde el blog del equipo NET CLR explica por qué los filtros de excepción son útiles blogs.msdn.com/clrteam/archive/2009/02/05/…
MarkJ
55
No solo está oculto, sino que tampoco está disponible en C #.
Cheeso
82

costumbre Enums

Una de las características ocultas reales de VB es la completionlistetiqueta de documentación XML que se puede usar para crear Enumtipos 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.

/EDITAR:

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.

Konrad Rudolph
fuente
Interesante: ¿podría mostrar un ejemplo de cómo se ve esto cuando lo consume?
Brian MacKay
Parece que alguien podría crear su propia regla llamando directamente al constructor de la regla. Si es así, y si desea detener esto, ¿podría declarar al constructor como "amigo" en su biblioteca?
Joel Coehoorn
Joel, en mi código de ejemplo, no lo prohibí. En cambio, ofrezco al usuario algunas reglas comunes y permito la creación de reglas propias y especializadas. Por supuesto, puede evitar esto marcando el constructor como friendo usando la misma clase que la enumeración: en Rulelugar de RuleTemplate.
Konrad Rudolph
¿hay algún lugar con una lista de usos de atributos útiles ocultos? Este en la cara parece increíble, pero aún no estoy seguro de dónde lo usaría o si podría resolver una queja primaria en algunos casos sin tener la capacidad de tener un genérico restringido a enumeraciones.
Maslow
@ Maslow: no hay ningún atributo involucrado aquí. Ese es un comentario xml.
Joel Coehoorn
49

¿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*"
Eduardo Molteni
fuente
3
¿esperar lo? ¡Eso es nuevo para mí! Hmm, eso es muchísimo mejor que la alternativa con la manipulación de cadenas VB.NET: D
STW
.. !! ¡No lo sabía aunque trabajé en varios proyectos de vb.net! Característica interesante ...
Meta-Knight
woooooooooooooooooooooooow! ¡Gracias! ¡Eso es asombroso! ¿Funciona en ELinq, DLinq también? ¿Qué pasa con XLinq?
Shimmy Weitzhandler
@dotjoe Hmm? No hay nada 'perezoso' en estos globos.
Josh Lee
¿Cómo funciona esto, qué sucede debajo del capó? ¿Es sinónimo de bibliotecas reg ex?
brumScouse
48

Typedefs

VB conoce un tipo primitivo de alias typedefví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)
Konrad Rudolph
fuente
2
muestre un ejemplo de que la palabra Importar no se reconoce en mi IDE.
Shimmy Weitzhandler
55
Importsdebería ser. ;-) De alguna manera, este error no se detectó (y obtuvo 28 votos a favor) durante casi todo un año.
Konrad Rudolph el
¡Siempre me pregunté cómo podría hacer un nuevo "tipo" con valores predeterminados para un genérico! ¡Frio!
eidylon
3
Importación, Importaciones, Importz, lo que sea! Sheesh, ¡crees que leemos estas publicaciones antes de votarlas!
MarkJ
Excelente para usar xunit en pruebas de estudio visual, es decirImports Assert = xUnit.Assert
wheelibin
45

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>
Nescio
fuente
Eso es lo que iba a decir. De hecho, he usado literales XML para un propósito en el que no estaba destinado. Lo usé para producir Javascript ... swortham.blogspot.com/2009/03/vb-2008.html
Steve Wortham
9
Entre otras cosas, puede usar XML Literals para evitar el escape de cadenas feo, por ejemplo, cuando usa cadenas que contienen comillas dobles. Sólo hay que poner la cadena dentro de un literal XML y llamar Valor, así: <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.)
Ryan Lundy
2
@ Kyralessa: +1, gran comentario. De hecho, también es una excelente manera de especificar cadenas de varias líneas (abraza las instrucciones SQL, etc.).
Heinzi
Inline XML es una de las peores características de VB.NET jamás concebidas. Hecho sin fundamento.
Grant Thomas
39

¡La inicialización de objetos también está ahí!

Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
Nescio
fuente
1
No puedo creer que fueran con llaves. Ya tenemos una declaración With ... podrían haber reutilizado esa sintaxis.
Sam Axe
2
Lo sé, está hecho solo para mostrarte que no hay policía en el camino ... jajaja JK
Shimmy Weitzhandler el
44
Esto es lo que sucede cuando todos los escritores de compiladores son en sí mismos programadores de C / C ++. Siguen deslizando la sintaxis de C a otros lenguajes porque no pueden concebir que algo sea mejor.
RBarryYoung
38

DirectCast

DirectCastes una maravilla En la superficie, funciona de manera similar al CTypeoperador en que convierte un objeto de un tipo a otro. Sin embargo, funciona con un conjunto de reglas mucho más estricto. CTypePor 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:

  • Unboxing de un tipo de valor, y
  • upcasting en la jerarquía de clases.

Cualquier otra conversión no funcionará (por ejemplo, tratar de descomprimir un Integera 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 DirectCastsiempre 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 DirectCastal CTypeoperador 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 CTypeoperador 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? )

Konrad Rudolph
fuente
De hecho, me gusta TryCast () un poco mejor. No arrojará una excepción, solo devuelve Nothing si el lanzamiento falla. Si espera que el reparto falle con frecuencia, es más rápido que If TypeOf x Is T ... DirectCast (x, T) y ciertamente más rápido que detectar la excepción si DirectCast falla.
Bob King
66
DirectCast () y TryCast () son invaluables cuando se usan correctamente como un par. DirectCast () debe usarse si siempre se espera que el objeto que se está lanzando sea ​​el tipo de destino (si no es así, obtendrá un error, algo bueno ya que es una situación inesperada). TryCast () debe usarse si el objeto que se está lanzando podría ser del tipo objetivo o de varios tipos objetivo. El uso exclusivo de Uno u otro generará una sobrecarga adicional (si el tipo de x es y, entonces la difusión directa (x, y) es ineficiente) o evitará errores válidos (usar TryCast () para los casos en que el objeto siempre debe ser el tipo de destino)
STW
Yoooder: 100% correcto. Es una lástima que no mencioné en TryCastese entonces, ya que principalmente tenía un hueso para elegir con el uso generalizado CType.
Konrad Rudolph
@Maslow: por supuesto que no, ya que las enumeraciones son tipos de valor y TryCastsolo funcionan en tipos de referencia, según la documentación.
Konrad Rudolph
+1: Je. Tengo que admitir que acabo de leer esto y pensé "Oh sí, DirectCast, ¿cómo me olvidé de eso?" Y luego lo usé en mi siguiente línea de código (ya que realmente no me gusta CType).
RBarryYoung
37

If operador condicional y de fusión

No 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 Ifoperador 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)
Konrad Rudolph
fuente
¡Bien, no sabía esto! Acabo de usar IIF ayer, así que voy a volver a visitar ese bloque de código.
Sean Gough
44
Dile a VS 2005 que. No todos trabajamos con lo último y lo mejor.
Sam Erwin
3
@Slough, tonterías. Este método es 100% seguro y devuelve un objeto del mismo tipo que su argumento (segundo y tercero). Además, debe haber una conversión de ampliación entre los argumentos, de lo contrario habrá un error de compilación porque los tipos no coinciden.
Konrad Rudolph el
1
Sí, su IIf () que no es de tipo seguro
Pondidum
2
@ Br.Bill De hecho, es completamente equivalente al :?operador de C y Perl , no es solo una versión simplificada.
Konrad Rudolph el
32

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
torial
fuente
55
En realidad se perdió un par: a) uso de "Seleccionar caso verdadero" para probar más de una variable, b) uso de formulario "Caso A, B, ...", e incluso c) aplicar el ":" a alinee la declaración de ejecución con la cláusula de condición (aunque a muchos no les gusta esto).
RBarryYoung
66
Por favor, no use Select Case True. Solo use una declaración If.
Ryan Lundy
44
Encuentro Select Case True mucho más fácil de leer que una declaración ifelse gigante.
dwidel
El problema Select Case Truees que parece que evalúa cada una de las Casedeclaraciones 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 Ifes mucho más clara a este respecto ( If...Else If...Else If...Else).
Ryan Lundy
31

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!

Jasha87
fuente
Pero también crea algunos errores ocultos, especialmente cuando tienes With inside With
Varun Mahajan
2
Ni siquiera sabía que podías poner un nuevo With dentro de un With existente. Eso es descuidado!
Bob King
2Bob: no es descuidado, sugeriría ... es solo una construcción de lenguaje para usar con cuidado. Para establecer muchas propiedades en líneas sucesivas, es genial, pero encontrar un .Foo aleatorio en un código complejo y luego tener que buscar las líneas anteriores de la declaración With no es un buen uso de la función.
ChrisA
2
Deseo C # tiene esto? ¿O he estado dormido y eso ya está en las respuestas ocultas de C # ...? ;-)
peSHIr
1
@Boo: Tienes razón, pero sigue siendo una molestia que no puedas agregarlo a la lista de vigilancia.
Meta-Knight
31

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 #

cjk
fuente
55
+1 Es extraño cómo la gente de C # corre a FileHelpers sin considerar esto. Estoy seguro de que FileHelpers es excelente, pero es una dependencia externa.
MarkJ
@ Mark J Supongo que es por ignorancia
Nathan Koop
Busqué en Google al intentar encontrar esta clase y nunca lo hice, ¡gracias por alardear!
pingoo
26
  • Operadores lógicos también / u otros

(EDITAR: Obtenga más información aquí: ¿Debería usar siempre los operadores AndAlso y OrElse? )

Joel Coehoorn
fuente
No lo llamaría oculto en absoluto, si el contacto no es nada y también el contacto.ContactId> 0 Entonces hágalo, si va a usar y se lanzará una excepción.
Shimmy Weitzhandler
25

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.

Joel Coehoorn
fuente
1
Un uso de esto es mantener un contador que se incrementará cada vez que se llame al método. Si la variable está marcada como Estática, no se reinicializará en cada llamada al método; solo se inicializará en la primera llamada y, a partir de entonces, conservará su valor.
Ryan Lundy
Esta es la razón por la cual los miembros de la clase estática se denominan "compartidos" en VB.NET
Enrico Campidoglio
Estático es una mala forma en VB.NET aún más que en VB clásico. Las variables estáticas deben evitarse siempre que sea posible.
Sam Axe
66
@Boo - eso es bastante amplio. ¿Cuál es tu justificación? Creo que las variables estáticas son útiles.
MarkJ
44
Estática, utilizada como en los ejemplos anteriores, permite una forma única de encapsulación: variables de nivel de clase que tienen un alcance de nivel de método. Sin él, tendría que crear una variable de nivel de clase que sería accesible para cualquier miembro de la clase, incluso si solo la está usando en un método.
Ryan Lundy
25

En vb hay una diferencia entre estos operadores:

/se Double
\está Integerignorando 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
Shimmy
fuente
1
Aprendí esto de la manera difícil cuando trataba de encontrar una aguja en un millón de líneas de código. división regular versus entera. ¡Buen consejo!
Jason Irwin
23

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:

  • Mi computadora : acceso a 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.Recursos : acceso a los recursos utilizados por la aplicación que reside en los archivos de recursos de una manera fuertemente tipada.
  • My.Settings : acceso a los ajustes de configuración de la aplicación de manera muy tipada.
splattne
fuente
Esto es genial y todos los chicos de vb.net deberían saber cosas en Mi espacio de nombres, es muy útil.
dr. mal
Mi. * FTW :).
dr. mal
3
Es algo útil, pero odio el nombre tonto. Me recuerda a este secretgeek.net/refactvb.asp
MarkJ
23

Eventos personalizados

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
Konrad Rudolph
fuente
Parece genial, pero si alguna vez necesito esto, creo que habré hecho algo mal ;-). Simplemente parece estar en contra del principio KISS.
chrissie1
44
Es realmente muy útil cuando quieres asegurarte de que cada receptor reciba el evento, incluso si uno o más arrojan una excepción.
Jonathan Allen el
Otro valor (lo acabo de leer en el sitio de MSDN) es que si su clase lanza muchos eventos, puede forzarlo a usar una tabla / diccionario hash como contenedor, en lugar de declarar un campo para cada evento. msdn.microsoft.com/en-us/library/8627sbea(VS.71).aspx
torial
Frio. Pensé que esta es una de las características que distinguen a C # y VB.NET (como en una lata, pero la otra no tiene sintaxis). Es bueno saber al menos que estaba equivocado a este respecto.
PERS
21

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.

torial
fuente
11
Esa es una de esas características que utilicé y luego olvidé intencionalmente. Ahorra algunas pulsaciones de teclas, pero se mete con mi código resaltado y legible. olvidando de nuevo a la derecha .... AHORA
STW
3
Interesante, pero no realmente útil. ¿Es este el tipo de cosas en las que trabaja el equipo de VB en lugar de agregar características faltantes como la palabra clave de rendimiento? : P
Meta-Knight
55
Esta característica se lleva para la compatibilidad con versiones anteriores de VB3 (AFAIK)
Eduardo Molteni
1
¿Las clases que implementan un índice con clave tienen una interfaz común de la que heredan? como IKeyed de la misma manera que los contenedores indexados enteros implementan IENumberable?
Maslow
2
Esta característica también funciona con DataRows (es decir, dr! ID), que es MUY útil en LINQ to DataSets.
Paul
19

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
torial
fuente
Estoy seguro de que puedes hacer algo así en C #. ¿En VB.NET es solo forzado, y en C # es opcional?
Jesper Blad Jensen
55
También puede hacer que el subprivado sea privado, lo cual es una excelente manera de ocultar cosas como las llamadas a versiones no genéricas de interfaces obsoletas.
Craig Gidney
3
Puede ser una buena idea El ejemplo clásico sería si desea un método de cierre público que también actúe como su implementación Dispose para IDisposable.
MarkJ
1
Eso también es bastante útil si implementa dos interfaces que comparten un nombre de método.
Eric Nicholson el
He visto esto y siempre deseo no haberlo hecho. No debería de ser permitido.
FastAl
17

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

Chris Haas
fuente
66
Oh, Dios mío ... esa es una característica notable, aunque no creo que sabría lo que estaba haciendo si lo leía en el código de otra persona. Si tiene que comentarlo solo para saber lo que está haciendo, también podría haber hecho que la variable descarte pase.
mattmc3
77
Esto es en realidad un efecto secundario del uso de paréntesis: los paréntesis crean un valor temporal de lo que hay dentro, incluso si solo hay un elemento. Este efecto ME MATÓ en vb6: las llamadas secundarias no tomaron parens, pero yo, desde C, instintivamente puse los parens. 6.0 explotó en múltiples parámetros, pero para un parámetro subs, felizmente pasó un valor temporal y se NEGÓ a honrar mi 'byref'. Sucedió cada 3 años, aproximadamente el tiempo que me llevó olvidar el último incidente.
FastAl
16

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")
rico
fuente
Wow, esto es super genial! Lo vi cuando utilicé los servicios web, etc., pero no sabía que pudieras hacer esto con ningún método normal.
RichC
2
Definitivamente una herramienta muy útil cuando encuentras un método que toma demasiados argumentos. Intento nombrar cada parámetro y poner el nombre: = valor en su propia línea. Es mucho más intuitivo y limpio para los métodos que toman parámetros> 5 (mi regla general).
STW
Especialmente útil para la automatización de Office, donde debe hacer frente a métodos con docenas de argumentos opcionales.
MarkJ
1
Lo que también es genial es que puede mezclar los dos: comience especificando los parámetros necesarios en orden, ¡luego cambie a los parámetros con nombre para los argumentos opcionales!
RBarryYoung
15

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
torial
fuente
23
Vale la pena señalar (solo porque lo he olvidado al menos dos veces) que puede tener una instrucción Using para envolver varios objetos desechables. La sintaxis es "Usar objA como un nuevo objeto, objB como un nuevo objeto ..." Es mucho más limpio que anidar múltiples declaraciones de Uso.
STW
Definitivamente uno de mis favoritos también.
Sam Axe
14

Los alias de importación también son en gran medida desconocidos:

Import winf = System.Windows.Forms

''Later
Dim x as winf.Form
torial
fuente
1
Creo que tuvimos la misma idea.
chrissie1
3
@Boo: aquí hay un ejemplo simple donde los alias de importación no son malos. stackoverflow.com/questions/92869/…
torial
De acuerdo, hay una vía obvia para el abuso, pero independientemente de la queja de @ torial, esta es una gran característica. Cada vez que incluyo System.Text.RegularExpressions me arriesgo a tener colisiones de nombres con la clase "Grupo", ya que es un nombre de clase común. El alias le permite evitar tener que calificar completamente las clases ambiguas, lo que ahorra mucho tiempo y en realidad mejora la legibilidad cuando se usa correctamente. La característica es excelente, pero su ejemplo específico invita a ridiculizar, lamento decirlo.
mattmc3
14

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

Technobabble
fuente
¿Por qué querrías hacer eso? No puedo imaginar un caso de uso en el que necesite saber la cantidad de suscriptores a un evento en VB.
Konrad Rudolph el
En ciertas circunstancias, C # arroja una excepción si aumenta el evento y no hay controladores. VB.Net no lo hará. De ahí la necesidad de verificar.
Joel Coehoorn
2
Utilicé esto para un evento de objeto comercial que generó mensajes de error de validación a los suscriptores. Quería verificar si el evento se estaba manejando para saber que se estaban recibiendo los errores de validación. De lo contrario, hice que el objeto comercial lanzara una excepción.
Technobabble
2
Otro uso útil para este miembro privado es obtener la lista de invocación del evento. Lo he usado en varios casos para disparar el evento de manera asíncrona a todas las personas que llaman (evita que el oyente A modifique el evento antes de que el oyente B lo reciba; también evita que el oyente A demore la entrega al oyente B). Lo he usado mucho en escenarios de sincronización de datos personalizados y también en API.
STW
14

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
torial
fuente
Creo que este ejemplo sería mejor si no utilizaras "If" como palabra clave de ejemplo.
Sean Gough
44
timer.Inicio y timer.Detener la primavera como ejemplos del buen uso de esto
Pondidum
55
+1 por señalarlo con un descargo de responsabilidad. Hay varias clases de marco que requieren que esto se resuelva correctamente, como [Asamblea]
STW
55
[Enum] es otro buen ejemplo de un caso en el que necesita los corchetes para usar la clase en lugar de la palabra clave.
Ryan Lundy
13

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

Ryan Lundy
fuente
3
<q>sería una buena etiqueta, similar al uso en Perl / Ruby. De todos modos, es un buen lenguaje. ¡ME GUSTA!
Konrad Rudolph
Qué idea tan genial. Gracias
Jeremy
12

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)
danlash
fuente
66
No si tienes Opción estricta
danlash
12

Puede tener 2 líneas de código en una sola línea. por lo tanto:

Dim x As New Something : x.CallAMethod
Parsa
fuente
Whoa ... pensé que esto sólo fue posible w / clase y la herencia
Jason
No olvidesCall (New Something).CallAMethod()
Jonathan Allen
Este es un holdever de MS-Basic en Apple] [! En mi tienda sería ridiculizado por usar Gotos: - /
FastAl
La mayoría de las veces esto debe evitarse, pero donde me gusta usarlo es en declaraciones de casos donde las líneas son realmente cortas, por ejemplo, Caso 4: x = 22
dwidel
11

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
Dr. mal
fuente
1
No sabía que C # los iba a conseguir. Son agradables, pero debe tener cuidado de usarlos solo cuando esté seguro de que C # no consumirá el código, ya que no los admite. FxCop / Code Analysis le indicará que sobrecargue el método.
STW
... Acabo de encontrar un gran uso para los parámetros opcionales, mientras los mantengo fuera del código de producción. Escribí una breve publicación al respecto en mi sitio: yoooder.com/wordpress/?p=62
STW
2
Ah, lo desprecio tanto ... Pero útil para la automatización de Office
dance2die
9

El título de caso en VB.Net se puede lograr con un viejo VB6 fxn:

StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
torial
fuente
1
también está en la clase textinfo. no estoy seguro de en qué espacio de nombres está. probablemente system.text
Shawn
Es mejor ser neutral en lenguaje .net y usar la clase Globalization TextInfo para convertir ToTitleCase. Si alguna vez necesita convertir el código a C #, tendrá muchas pequeñas molestias que requieren Microsoft.VisualBasic
Jeremy
9

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
torial
fuente
Esto es interesante, pero no estoy completamente seguro de dónde sería útil. myObj.Something ("abc") se parece más a que está accediendo a una Función que a una propiedad. No estoy seguro de lo que esto te compra.
mattmc3
Odio la ambigüedad. Que debería ser. Un método o una propiedad. Algunas herramientas de refactorización sugieren la creación tanto en ciertas situaciones también, parece que incluso no saben ...
brumScouse