vb.net hidden-features

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