Compartir vía


Novedades de Visual Basic

En este artículo se enumeran los nombres de características clave para cada versión de Visual Basic, con descripciones detalladas de las características nuevas y mejoradas en las versiones más recientes del lenguaje.

Versión actual

Visual Basic 16.9 / Visual Studio 2019, versión 16.9
Para ver las nuevas características, consulte Visual Basic 16.9.

Puede descargar el SDK de .NET más reciente desde la página de descargas de .NET.

Versiones anteriores

Visual Basic 16.0 / Visual Studio 2019, versión 16.0
Para ver las nuevas características, consulte Visual Basic 16.0.

Visual Basic 15.5 / Visual Studio 2017, versión 15.5
Para ver las nuevas características, consulte Visual Basic 15.5.

Visual Basic 15.3 / Visual Studio 2017, versión 15.3
Para ver las nuevas características, consulte Visual Basic 15.3.

Visual Basic 15/Visual Studio 2017
Para ver las nuevas características, consulte Visual Basic 2017.

Visual Basic/Visual Studio 2015
Para ver las nuevas características, consulte Visual Basic 14.

Visual Basic/Visual Studio 2013
Versiones preliminares de tecnología de .NET Compiler Platform ("Roslyn")

Visual Basic/Visual Studio 2012
Async y await palabras clave, iteradores, atributos de información del autor de la llamada

Visual Basic, Visual Studio 2010
Propiedades implementadas automáticamente, inicializadores de colección, continuación de línea implícita, dinámica, varianza genérica de co/contra, acceso global al espacio de nombres

Visual Basic/Visual Studio 2008
Language Integrated Query (LINQ), literales XML, inferencia de tipos locales, inicializadores de objetos, tipos anónimos, métodos de extensión, inferencia de tipos locales var , expresiones lambda, if operador, métodos parciales, tipos de valor que aceptan valores NULL

Visual Basic/Visual Studio 2005
El My tipo y los tipos auxiliares (acceso a la aplicación, el equipo, el sistema de archivos, la red)

Visual Basic/Visual Studio .NET 2003
Operadores de desplazamiento de bits, declaración de variable de bucle

Visual Basic/Visual Studio .NET 2002
La primera versión de Visual Basic .NET

Visual Basic 16.9

Visual Basic 16.9 permite el consumo de propiedades solo iniciales.

Visual Basic 16.0

Visual Basic 16.0 se centra en proporcionar más características de Visual Basic Runtime (microsoft.visualbasic.dll) a .NET Core y es la primera versión de Visual Basic centrada en .NET Core. Las partes del runtime de Visual Basic que dependen de WinForms se agregaron en .NET Core 3.0.

Comentarios permitidos en más lugares dentro de instrucciones

En Visual Basic 15.5 y versiones anteriores, los comentarios solo se permiten en líneas en blanco, al final de una instrucción o en lugares específicos dentro de una instrucción donde se permite una continuación de línea implícita. A partir de Visual Basic 16.0, también se permiten comentarios después de las continuaciones explícitas de línea y dentro de una instrucción en una línea que comienza con un espacio seguido de un carácter de subrayado.

Public Sub Main()
    cmd.CommandText = ' Comment is allowed here without _
        "SELECT * FROM Titles JOIN Publishers " _ ' This is a comment
        & "ON Publishers.PubId = Titles.PubID " _
 _ ' This is a comment on a line without code
        & "WHERE Publishers.State = 'CA'"
End Sub

Conversión optimizada de punto flotante a entero

En versiones anteriores de Visual Basic, la conversión de valores Double y Single a enteros ofrecía un rendimiento relativamente deficiente. Visual Basic 16.0 mejora significativamente el rendimiento de conversiones de punto flotante a enteros cuando se pasa el valor devuelto por cualquiera de los métodos siguientes a una de las funciones intrínsecas de conversión de enteros de Visual Basic (CByte, CShort, CInt, CLng, CSByte, CUShort, CUInt, CULng), o cuando el valor devuelto por cualquiera de los métodos siguientes se convierte implícitamente en un tipo entero cuando Option Strict se establece Offen :

Esta optimización permite que el código se ejecute más rápido, hasta dos veces más rápido para el código que realiza un gran número de conversiones a tipos enteros. En el ejemplo siguiente se muestran algunas llamadas de método simples que se ven afectadas por esta optimización:

Dim s As Single = 173.7619
Dim d As Double = s

Dim i1 As Integer = CInt(Fix(s))               ' Result: 173
Dim b1 As Byte = CByte(Int(d))                 ' Result: 173
Dim s1 AS Short = CShort(Math.Truncate(s))     ' Result: 173
Dim i2 As Integer = CInt(Math.Ceiling(d))      ' Result: 174
Dim i3 As Integer = CInt(Math.Round(s))        ' Result: 174

Tenga en cuenta que esto trunca en lugar de redondear valores de punto flotante.

Visual Basic 15.5

Argumentos con nombre no finales

En Visual Basic 15.3 y versiones anteriores, cuando una llamada al método incluía argumentos tanto por posición como por nombre, los argumentos posicionales tenían que preceder a los argumentos con nombre. A partir de Visual Basic 15.5, los argumentos posicionales y con nombre pueden aparecer en cualquier orden siempre que todos los argumentos hasta el último argumento posicional estén en la posición correcta. Esto resulta especialmente útil cuando se usan argumentos con nombre para que el código sea más legible.

Por ejemplo, la siguiente llamada al método tiene dos argumentos posicionales entre un argumento con nombre. El argumento con nombre deja claro que el valor 19 representa una edad.

StudentInfo.Display("Mary", age:=19, #9/21/1998#)

Private Protected modificador de acceso de miembro

Esta nueva combinación de palabras clave define un miembro al que pueden acceder todos los miembros de su clase contenedora, así como por tipos derivados de la clase contenedora, pero solo si también se encuentran en el ensamblado contenedor. Dado que las estructuras no se pueden heredar, Private Protected solo se pueden aplicar a los miembros de una clase.

Separador hexadecimal/ binario/octal inicial

Visual Basic 2017 agregó compatibilidad con el carácter de subrayado (_) como separador de dígitos. A partir de Visual Basic 15.5, puede usar el carácter de subrayado como separador inicial entre el prefijo y los dígitos hexadecimales, binarios o octales. En el ejemplo siguiente se usa un separador de dígitos inicial para definir 3.271.948.384 como un número hexadecimal:

Dim number As Integer = &H_C305_F860

Para usar el carácter de subrayado como separador inicial, debe agregar el siguiente elemento al archivo del proyecto de Visual Basic (*.vbproj):

<PropertyGroup>
  <LangVersion>15.5</LangVersion>
</PropertyGroup>

Visual Basic 15.3

Inferencia de tupla con nombre

Al asignar el valor de los elementos de tupla de variables, Visual Basic deduce el nombre de los elementos de tupla a partir de los nombres de variable correspondientes; no es necesario asignar un nombre explícito a un elemento de tupla. En el ejemplo siguiente se usa la inferencia para crear una tupla con tres elementos con nombre, state, stateNamey capital.

Const state As String = "MI"
Const stateName As String = "Michigan"
Const capital As String = "Lansing"
Dim stateInfo = (state, stateName, capital)
Console.WriteLine($"{stateInfo.stateName}: 2-letter code: {stateInfo.State}, Capital {stateInfo.capital}")
' The example displays the following output:
'      Michigan: 2-letter code: MI, Capital Lansing

Modificadores de compilador adicionales

El compilador de línea de comandos de Visual Basic ahora admite las opciones del compilador -refout y -refonly para controlar la salida de los ensamblados de referencia. -refout define el directorio de salida del ensamblado de referencia y -refonly especifica que solo se va a generar un ensamblado de referencia mediante la compilación.

Visual Basic 15

Tuplas

Las tuplas son una estructura de datos ligera que normalmente se usa para devolver varios valores desde una sola llamada de método. Normalmente, para devolver varios valores de un método, debe realizar una de las acciones siguientes:

  • Defina un tipo personalizado (o Class ).Structure Se trata de una solución de peso pesado.

  • Defina uno o varios ByRef parámetros, además de devolver un valor del método .

La compatibilidad de Visual Basic con tuplas le permite definir rápidamente una tupla, asignar opcionalmente nombres semánticos a sus valores y recuperar rápidamente sus valores. En el ejemplo siguiente se ajusta una llamada al TryParse método y se devuelve una tupla.

Imports System.Globalization

Public Module NumericLibrary
    Public Function ParseInteger(value As String) As (Success As Boolean, Number As Integer)
        Dim number As Integer
        Return (Integer.TryParse(value, NumberStyles.Any, CultureInfo.InvariantCulture, number), number)
    End Function
End Module

A continuación, puede llamar al método y controlar la tupla devuelta con código como el siguiente.

Dim numericString As String = "123,456"
Dim result = ParseInteger(numericString)
Console.WriteLine($"{If(result.Success, $"Success: {result.Number:N0}", "Failure")}")
Console.ReadLine()
'      Output: Success: 123,456

Literales binarios y separadores de dígitos

Puede definir un literal binario mediante el prefijo &B o &b. Además, puede usar el carácter de subrayado, _, como separador de dígitos para mejorar la legibilidad. En el ejemplo siguiente se usan ambas características para asignar un Byte valor y mostrarlo como un número decimal, hexadecimal y binario.

Dim value As Byte = &B0110_1110
Console.WriteLine($"{NameOf(value)}  = {value} (hex: 0x{value:X2}) " +
                  $"(binary: {Convert.ToString(value, 2)})")
' The example displays the following output:
'      value  = 110 (hex: 0x6E) (binary: 1101110)      

Para obtener más información, vea la sección "Asignaciones literales" de los tipos de datos Byte, Integer, Long, Short, SByte, UInteger, ULong y UShort .

Compatibilidad con valores devueltos de referencia de C#

C# admite valores devueltos de referencia. Es decir, cuando el método de llamada recibe un valor devuelto por referencia, puede cambiar el valor de la referencia. Visual Basic no permite crear métodos con valores devueltos de referencia, pero permite consumir y modificar los valores devueltos de referencia.

Por ejemplo, la siguiente Sentence clase escrita en C# incluye un FindNext método que encuentra la siguiente palabra en una oración que comienza con una subcadena especificada. La cadena se devuelve como un valor devuelto de referencia y una Boolean variable pasada por referencia al método indica si la búsqueda se realizó correctamente. Esto significa que, además de leer el valor devuelto, el autor de la llamada también puede modificarlo y esa modificación se refleja en la Sentence clase .

using System;

public class Sentence
{
    private string[] words;
    private int currentSearchPointer;

    public Sentence(string sentence)
    {
        words = sentence.Split(' ');
        currentSearchPointer = -1;
    }

    public ref string FindNext(string startWithString, ref bool found)
    {
        for (int count = currentSearchPointer + 1; count < words.Length; count++)
        {
            if (words[count].StartsWith(startWithString))
            {
                currentSearchPointer = count;
                found = true;
                return ref words[currentSearchPointer];
            }
        }
        currentSearchPointer = -1;
        found = false;
        return ref words[0];
    }

    public string GetSentence()
    {
        string stringToReturn = null;
        foreach (var word in words)
            stringToReturn += $"{word} ";

        return stringToReturn.Trim();
    }
}

En su forma más sencilla, puede modificar la palabra que se encuentra en la oración mediante código como el siguiente. Tenga en cuenta que no está asignando un valor al método, sino a la expresión que devuelve el método, que es el valor devuelto de referencia.

Dim sentence As New Sentence("A time to see the world is now.")
Dim found = False
sentence.FindNext("A", found) = "A good" 
Console.WriteLine(sentence.GetSentence()) 
' The example displays the following output:
'      A good time to see the world is now.

Sin embargo, un problema con este código es que, si no se encuentra una coincidencia, el método devuelve la primera palabra. Dado que el ejemplo no examina el valor del Boolean argumento para determinar si se encuentra una coincidencia, modifica la primera palabra si no hay ninguna coincidencia. En el ejemplo siguiente se corrige esto reemplazando la primera palabra por sí misma si no hay ninguna coincidencia.

Dim sentence As New Sentence("A time to see the world is now.")
Dim found = False
sentence.FindNext("A", found) = IIf(found, "A good", sentence.FindNext("B", found)) 
Console.WriteLine(sentence.GetSentence()) 
' The example displays the following output:
'      A good time to see the world is now.

Una mejor solución consiste en usar un método auxiliar al que se pasa el valor devuelto de referencia por referencia. A continuación, el método auxiliar puede modificar el argumento que se le pasa por referencia. En el ejemplo siguiente se hace eso.

Module Example
   Public Sub Main()
      Dim sentence As New Sentence("A time to see the world is now.")
      Dim found = False
      Dim returns = RefHelper(sentence.FindNext("A", found), "A good", found) 
      Console.WriteLine(sentence.GetSentence()) 
   End Sub
   
   Private Function RefHelper(ByRef stringFound As String, replacement As String, success As Boolean) _ 
                    As (originalString As String, found As Boolean) 
      Dim originalString = stringFound
      If found Then stringFound = replacement
      Return (originalString, found)   
   End Function
End Module
' The example displays the following output:
'      A good time to see the world is now.

Para obtener más información, vea Valores devueltos de referencia.

Visual Basic 14

NameOf

Puede obtener el nombre de cadena no calificado de un tipo o miembro para usarlo en un mensaje de error sin codificar una cadena de forma rígida. Esto permite que el código permanezca correcto al refactorizar. Esta característica también es útil para enlazar vínculos MVC del controlador de vista del modelo y desencadenar eventos modificados de propiedades.

Interpolación de cadenas

Puede usar expresiones de interpolación de cadenas para construir cadenas. Una expresión de cadena interpolada es similar a una cadena de plantilla que contiene expresiones. Una cadena interpolada es más fácil de entender con respecto a los argumentos que el formato compuesto.

Acceso y indexación de miembros condicionales NULL

Puede probar null de una manera sintáctica muy ligera antes de realizar una operación de acceso a miembros (?.) o índice (?[]). Estos operadores le ayudan a escribir menos código para controlar comprobaciones nulas, especialmente para descendentes en estructuras de datos. Si el operando izquierdo o la referencia de objeto es NULL, las operaciones devuelven null.

Literales de cadena de varias líneas

Los literales de cadena pueden contener secuencias de nueva línea. Ya no necesita el antiguo trabajo de uso <xml><![CDATA[...text with newlines...]]></xml>.Value

Comentarios

Puede colocar comentarios después de las continuaciones de línea implícitas, dentro de las expresiones del inicializador y entre los términos de expresión LINQ.

Resolución de nombres completa más inteligente

Dado código como Threading.Thread.Sleep(1000), Visual Basic se usó para buscar el espacio de nombres "Threading", detectar que era ambiguo entre System.Threading y System.Windows.Threading y, a continuación, notificar un error. Visual Basic ahora considera ambos posibles espacios de nombres juntos. Si muestra la lista de finalización, el editor de Visual Studio enumera los miembros de ambos tipos en la lista de finalización.

Literales de fecha de año

Puede tener literales de fecha en formato aaaa-mm-dd, #2015-03-17 16:10 PM#.

Propiedades de la interfaz readonly

Puede implementar propiedades de interfaz readonly mediante una propiedad readwrite. La interfaz garantiza la funcionalidad mínima y no impide que se establezca una clase de implementación.

TypeOf <expr> IsNot <type>

Para obtener más legibilidad del código, ahora puede usar TypeOf con IsNot.

id.> de advertencia <de #Disable y id. de advertencia <de #Enable>

Puede deshabilitar y habilitar advertencias específicas para regiones dentro de un archivo de origen.

Mejoras en los comentarios de documentos XML

Al escribir comentarios de documentos, obtendrá compatibilidad con el editor inteligente y la compilación para validar los nombres de parámetros, el control adecuado de crefs (genéricos, operadores, etc.), el coloreado y la refactorización.

Definiciones parciales de módulo e interfaz

Además de las clases y estructuras, puede declarar módulos e interfaces parciales.

#Region directivas dentro de los cuerpos del método

Puede colocar #Region...#End delimitadores de región en cualquier lugar de un archivo, dentro de funciones e incluso abarcar entre cuerpos de función.

Las definiciones de invalidaciones son sobrecargas implícitas

Si agrega el Overrides modificador a una definición, el compilador agrega Overloads implícitamente para que pueda escribir menos código en casos comunes.

CObj permitido en los argumentos de atributos

El compilador usado para dar un error que CObj(...) no era una constante cuando se usaba en construcciones de atributos.

Declarar y consumir métodos ambiguos de diferentes interfaces

Anteriormente, el código siguiente generaba errores que le impedían declarar IMock o llamar a GetDetails (si se habían declarado en C#):

Interface ICustomer
  Sub GetDetails(x As Integer)
End Interface

Interface ITime
  Sub GetDetails(x As String)
End Interface

Interface IMock : Inherits ICustomer, ITime
  Overloads Sub GetDetails(x As Char)
End Interface

Interface IMock2 : Inherits ICustomer, ITime
End Interface

Ahora el compilador usará reglas de resolución de sobrecarga normales para elegir el más adecuado GetDetails para llamar a y puede declarar relaciones de interfaz en Visual Basic como las que se muestran en el ejemplo.

Consulte también