Cheatsheet Visual Basic
Linguagem da Microsoft para aplicações Windows, Office e automação
Visual Basic
Básico e Estrutura
Estructura del programa
Imports System
Module Program
Sub Main(args As String())
Console.WriteLine("¡Hola Mundo!")
Console.Write("Nombre: ")
Dim nombre = Console.ReadLine()
Console.WriteLine($"¡Hola, {nombre}!")
End Sub
End ModuleUn programa de consola VB.NET comienza en un Module con el método Sub Main. El Imports trae namespaces y el Console escribe en pantalla.
Operadores de comparación y lógicos
Dim x = 10
' Comparación (devuelven Boolean):
Dim r1 = x = 10 ' True
Dim r2 = x <> 5 ' True (distinto)
Dim r3 = x >= 10 ' True
' Lógicos:
Dim ok = r1 And r2
Dim ok2 = r1 Or r3
Dim neg = Not r1
' Cortocircuito (recomendado):
If x > 0 AndAlso x < 100 Then
Console.WriteLine("entre 0 y 100")
End IfAndAlso y OrElse son las versiones de cortocircuito: dejan de evaluar en cuanto el resultado se conoce, evitando errores y ganando rendimiento.
Option Strict y Option Infer
' En la parte superior del archivo:
Option Strict On ' prohíbe conversiones implícitas
Option Infer On ' permite inferir tipos
Option Explicit On ' obliga a declarar variables
' Con Option Strict On, esto da error:
' Dim n As Integer = "42" ' ¡error!
' Hay que convertir explícitamente:
Dim n As Integer = CInt("42")
' Inferencia:
Dim lista = New List(Of String)() ' tipo inferidoOption Strict On es una buena práctica: impide conversiones automáticas que esconden bugs. Option Infer On deja al compilador deducir el tipo a partir del valor.
Variables con Dim
Dim nombre As String = "VB.NET" Dim edad As Integer = 30 Dim activo As Boolean = True Dim pi As Double = 3.14 Dim precio As Decimal = 99.99D ' Inferencia de tipo (Option Infer On): Dim x = 42 ' Integer Dim s = "Hola" ' String Const MAX As Integer = 100
Las variables se declaran con Dim. El tipo puede ser explícito (As Integer) o inferido por el valor. Const crea constantes inmutables.
Concatenación de strings
Dim nombre = "Ana" Dim apellido = "Silva" ' Operador & (concatenación): Dim completo = nombre & " " & apellido ' Operador + (también funciona): Dim s = "Hola " + nombre ' Juntar con números: Dim edad = 30 Dim msg = nombre & " tiene " & edad & " años" Console.WriteLine(completo) ' Ana Silva
El operador & es el recomendado para concatenar, pues convierte automáticamente números en texto. El + puede causar ambigüedad con la suma.
Comentarios
' Esto es un comentario de línea
Dim x = 10 ' comentario al final de la línea
REM También funciona (antiguo, poco usado)
''' <summary>
''' Comentario de documentación XML
''' </summary>
''' <param name="n">El número</param>
Function Doble(n As Integer) As Integer
Return n * 2
End FunctionEl despuéstrofo &después; inicia un comentario. Los comentarios XML con &después;&después;&después; generan documentación IntelliSense para los métodos.
Tipos de datos
' Enteros: Byte, Short, Integer, Long ' Decimales: Single, Double, Decimal ' Otros: Boolean, Char, String, Date, Object Dim n As Integer = 42 Dim d As Date = #2024-01-15# Dim c As Char = "A"c Dim o As Object = "cualquier cosa" ' Sufijos de literal: Dim l = 100L ' Long Dim f = 1.5F ' Single Dim dec = 9.9D ' Decimal
VB.NET usa los tipos de .NET. Los literales de fecha van entre #, y sufijos como L, F y D indican el tipo numérico.
Operador ternario If()
Dim edad = 20 ' If(condición, valorSiVerdadero, valorSiFalso) Dim estado = If(edad >= 18, "Adulto", "Menor") Console.WriteLine(estado) ' Adulto ' Coalescencia (primero no-Nothing): Dim nombre As String = Nothing Dim mostrado = If(nombre, "Anónimo") Console.WriteLine(mostrado) ' Anónimo
La función If() con 3 argumentos actúa como un ternario. Con 2 argumentos, funciona como coalescencia: devuelve el primer valor que no sea Nothing.
Continuación de línea
' VB.NET moderno: salto automático en la mayoría de los casos
Dim resultado = 1 + 2 +
3 + 4
Dim lista = New List(Of String) From {
"Ana",
"Ray",
"Mia"
}
' Antiguo (VB9 y anteriores): usar _ (guion bajo)
Dim total = 1 + _
2 + 3En las versiones modernas el salto de línea es automático en operadores y listas. En código antiguo se usaba el carácter de continuación _ (guion bajo) al final de la línea.
Operadores aritméticos
Dim a = 10, b = 3 Dim suma = a + b ' 13 Dim dif = a - b ' 7 Dim prod = a * b ' 30 Dim divReal = a / b ' 3.333... (Double) Dim divEnt = a \ b ' 3 (división entera) Dim resto = a Mod b ' 1 Dim pot = 2 ^ 10 ' 1024 a += 1 ' a = a + 1 a -= 1 ' a = a - 1
La barra / hace división real y la barra invertida \ hace división entera. Mod da el resto y ^ la potencia.
Conversiones de tipo
' Funciones de conversión:
Dim n = CInt("42") ' String -> Integer
Dim d = CDbl("3.14") ' String -> Double
Dim s = CStr(42) ' Integer -> String
Dim b = CBool(1) ' -> Boolean
Dim dt = CDate("2024-01-15") ' -> Date
' Conversión segura (no lanza excepción):
Dim resultado As Integer
Dim ok = Integer.TryParse("42", resultado) ' True
' ToString:
Dim txt = 42.ToString() ' "42"
Dim fmt = 3.14159.ToString("F2") ' "3.14"Las funciones CInt, CDbl y CStr convierten tipos. Para evitar excepciones con texto inválido, usa TryParse, que devuelve True o False.
Múltiples declaraciones
' Varias variables en la misma línea: Dim x = 1, y = 2, z = 3 ' Mismo tipo explícito: Dim a, b, c As Integer ' ¡solo c es Integer! ' a y b quedan Object (cuidado) ' Forma segura: Dim i As Integer = 0 Dim j As Integer = 0 ' Asignación compuesta: x += 5 ' x = x + 5 y *= 2 ' y = y * 2
Atención: en Dim a, b, c As Integer solo c queda Integer; los demás quedan Object. Prefiere declarar cada variable con su tipo.
Funções e Procedimentos
Function (con retorno)
Function Sumar(a As Integer, b As Integer) As Integer
Return a + b
End Function
' Llamar:
Dim r = Sumar(3, 4) ' 7
' Function de expresión única:
Function Doble(n As Integer) As Integer
Return n * 2
End FunctionUna Function devuelve un valor con Return y declara el tipo de retorno con As. El nombre de la función describe lo que hace.
ByVal y ByRef
' ByVal (copia - es el default):
Sub Incrementar(ByVal n As Integer)
n += 1 ' no afecta al original
End Sub
' ByRef (referencia - cambia el original):
Sub Intercambiar(ByRef a As Integer, ByRef b As Integer)
Dim temp = a
a = b
b = temp
End Sub
Dim x = 1, y = 2
Intercambiar(x, y) ' x = 2, y = 1ByVal pasa una copia (el original no cambia); ByRef pasa la referencia (el original se modifica). En VB.NET el estándar es ByVal.
Métodos de extensión
Imports System.Runtime.CompilerServices
<Extension()>
Function Repetir(s As String, n As Integer) As String
Return String.Concat(Enumerable.Repeat(s, n))
End Function
' Uso como si fuera método de String:
Dim r = "ab".Repetir(3) ' "ababab"Los métodos de extensión añaden métodos a tipos existentes sin modificarlos. Necesitan el atributo <Extension()> y un Module; el 1er parámetro es el tipo extendido.
Sub (sin retorno)
Sub Imprimir(msg As String)
Console.WriteLine(msg)
End Sub
' Llamar:
Imprimir("¡Hola!")
' Sub puede terminar antes con Exit Sub:
Sub Validar(n As Integer)
If n < 0 Then Exit Sub
Console.WriteLine(n)
End SubUna Sub ejecuta acciones sin devolver valor. Usa Exit Sub para terminar antes del final. Es ideal para procedimientos de impresión o validación.
Funciones lambda
' Lambda de una expresión:
Dim doble = Function(x As Integer) x * 2
Dim suma = Function(a As Integer, b As Integer) a + b
Console.WriteLine(doble(5)) ' 10
Console.WriteLine(suma(3, 4)) ' 7
' Lambda Sub (sin retorno):
Dim imprimir = Sub(msg As String) Console.WriteLine(msg)
imprimir("Hola")Una lambda es una función anónima corta. Function(...) devuelve un valor; Sub(...) ejecuta una acción. Se usan mucho con LINQ y eventos.
Propiedades
Private _nombre As String
Public Property Nombre As String
Get
Return _nombre
End Get
Set(value As String)
_nombre = value.Trim()
End Set
End Property
' Auto-property (sin campo manual):
Public Property Edad As Integer
' Solo lectura:
Public ReadOnly Property NombreMayusculas As String
Get
Return _nombre.ToUpper()
End Get
End PropertyUna Property expone un campo con Get y Set. Las auto-properties evitan el campo privado. ReadOnly crea propiedades de solo lectura.
Parámetros opcionales y con nombre
Function Saludar(nombre As String,
Optional prefijo As String = "Hola") As String
Return $"{prefijo}, {nombre}!"
End Function
' Usar valor por defecto:
Console.WriteLine(Saludar("Ana")) ' Hola, Ana!
' Argumento con nombre:
Console.WriteLine(Saludar("Ray", prefijo:="Buenos días"))Los parámetros con Optional necesitan un valor por defecto. Los argumentos con nombre (prefijo:=) permiten saltar parámetros opcionales con claridad.
Lambda multilínea
Dim factorial = Function(n As Integer)
If n <= 1 Then Return 1
Return n * factorial(n - 1)
End Function
Console.WriteLine(factorial(5)) ' 120
Dim clasificar = Function(n As Integer)
If n > 0 Then Return "positivo"
If n < 0 Then Return "negativo"
Return "zero"
End FunctionLas lambdas de varias líneas terminan con End Function (o End Sub). El cuerpo puede tener If, bucles y múltiples Return.
Iteradores (Yield)
Function Contar(max As Integer) As IEnumerable(Of Integer)
For i = 1 To max
Yield i
Next
End Function
' Consumo perezoso:
For Each n In Contar(5)
Console.WriteLine(n) ' 1 2 3 4 5
NextEl Yield devuelve un elemento cada vez, creando una secuencia perezosa. La función retorna IEnumerable(Of T) y solo genera valores al recorrerla.
ParamArray (nº variable de argumentos)
Function SumarTodo(ParamArray nums() As Integer) As Integer
Dim total = 0
For Each n In nums
total += n
Next
Return total
End Function
' Llamar con varios argumentos:
Console.WriteLine(SumarTodo(1, 2, 3)) ' 6
Console.WriteLine(SumarTodo(10, 20, 30, 40)) ' 100ParamArray acepta un número variable de argumentos, tratados como un array dentro de la función. Debe ser el último parámetro de la lista.
Funciones locales (Local Functions)
Function Calcular(n As Integer) As Integer
' Función local, solo visible aquí dentro:
Function Cuadrado(x As Integer) As Integer
Return x * x
End Function
Return Cuadrado(n) + Cuadrado(n + 1)
End Function
Console.WriteLine(Calcular(3)) ' 9 + 16 = 25Las funciones locales se declaran dentro de otra Function y solo existen en ese ámbito. Ayudan a organizar lógica auxiliar sin ensuciar la clase.
Funciones recursivas
Function Fibonacci(n As Integer) As Long
If n <= 1 Then Return n
Return Fibonacci(n - 1) + Fibonacci(n - 2)
End Function
For i = 0 To 10
Console.Write(Fibonacci(i) & " ")
Next
' 0 1 1 2 3 5 8 13 21 34 55Una función recursiva se llama a sí misma. Siempre necesita un caso base (If n <= 1 Then Return n) para parar, si no entra en bucle infinito.
Strings e Formatação
Métodos de String
Dim s As String = "Hello World"
Console.WriteLine(s.Length) ' 11
Console.WriteLine(s.ToUpper()) ' "HELLO WORLD"
Console.WriteLine(s.ToLower()) ' "hello world"
Console.WriteLine(s.Substring(0, 5)) ' "Hello"
Console.WriteLine(s.Contains("World")) ' True
Console.WriteLine(s.Replace("World", "VB"))
Console.WriteLine(s.Trim()) ' elimina espacios
Console.WriteLine(s.IndexOf("World")) ' 6Las strings tienen métodos como ToUpper, Substring, Contains y Replace. Las strings son inmutables: cada método devuelve una nueva string.
Verbatim y escape
' Las comillas dobles se escapan duplicando: Dim s = "Él dijo ""Hola""" ' Rutas de archivo (sin escape de \): Dim path = "C:\Users\Ana\docs" ' Nueva línea y tabulación: Dim texto = "Línea1" & vbCrLf & "Línea2" & vbTab & "fin" ' Constantes útiles: Console.WriteLine(vbCrLf) ' nueva línea (Windows) Console.WriteLine(vbTab) ' tabulación Console.WriteLine(vbNullString) ' string vacía
En VB.NET las comillas se escapan duplicando (""), no con barra. vbCrLf y vbTab son constantes para nueva línea y tabulación.
Trabajar con fechas
Dim hoy = Date.Now
Dim fecha = #2024-01-15#
Console.WriteLine(hoy.Year)
Console.WriteLine(hoy.Month)
Console.WriteLine(hoy.Day)
Console.WriteLine(hoy.DayOfWeek)
' Formatear:
Console.WriteLine(hoy.ToString("dd/MM/yyyy"))
Console.WriteLine(hoy.ToString("yyyy-MM-dd HH:mm"))
' Aritmética de fechas:
Dim manana = hoy.AddDays(1)
Dim diff = (manana - hoy).TotalDays ' 1El tipo Date (o DateTime) tiene propiedades Year, Month, Day. Métodos como AddDays suman tiempo y la resta da un TimeSpan.
Split y Join
Dim csv = "Ana,Ray,Mia"
' Separar por carácter:
Dim partes = csv.Split(","c)
For Each p In partes
Console.WriteLine(p)
Next
' Separar por varios separadores:
Dim frase = "uno dos;tres"
Dim words = frase.Split({" "c, ";"c}, StringSplitOptions.RemoveEmptyEntries)
' Juntar:
Dim junto = String.Join(" | ", partes) ' "Ana | Ray | Mia"Split divide una string en un array por un separador (el sufijo c indica un Char). String.Join junta elementos con un delimitador.
StringBuilder
Imports System.Text
Dim sb As New StringBuilder()
For i = 1 To 5
sb.Append("Línea ").AppendLine(i.ToString())
Next
sb.Insert(0, "=== Inicio ===" & vbCrLf)
sb.Replace("Línea", "Item")
Dim resultado = sb.ToString()
Console.WriteLine(resultado)El StringBuilder es eficiente para construir strings en bucles, pues no crea un objeto nuevo con cada cambio. Usa Append, AppendLine y ToString.
Conversiones de texto
Dim s = "123"
' Texto a número:
Dim n = Integer.Parse(s)
Dim d = Double.Parse("3.14")
' Número a texto:
Dim txt = n.ToString()
Dim hex = 255.ToString("X") ' "FF"
Dim bin = Convert.ToString(5, 2) ' "101"
' Carácter a código:
Dim code = Asc("A") ' 65
Dim letra = Chr(65) ' "A"Parse convierte texto en número (lanza excepción si es inválido). Asc da el código de un carácter y Chr hace lo inverso.
Interpolación de strings
Dim nombre = "Ana"
Dim edad = 30
' Interpolación con $:
Console.WriteLine($"{nombre} tiene {edad} años")
Console.WriteLine($"En 5 años: {edad + 5}")
' Con alineación y formato:
Console.WriteLine($"|{nombre,-10}|{edad,5}|")
' String multilínea:
Dim texto = $"Hola {nombre},
¡bienvenida!"La interpolación con $ inserta expresiones dentro de {}. Puedes alinear con coma ({nombre,-10}) y formatear con dos puntos.
Comparación de strings
Dim a = "Hola"
Dim b = "hola"
' Sensible a mayúsculas:
Console.WriteLine(a = b) ' False
' Ignorando mayúsculas:
Console.WriteLine(String.Equals(a, b, StringComparison.OrdinalIgnoreCase)) ' True
Console.WriteLine(a.Equals(b, StringComparison.CurrentCultureIgnoreCase))
' Comparar orden:
Console.WriteLine(String.Compare("abc", "abd")) ' negativoPor defecto la comparación distingue mayúsculas. Usa StringComparison.OrdinalIgnoreCase para ignorar la capitalización en Equals y Compare.
Verificar contenido de string
Dim s = "Hola Mundo"
Console.WriteLine(s.StartsWith("Hola")) ' True
Console.WriteLine(s.EndsWith("Mundo")) ' True
Console.WriteLine(s.Contains("Mun")) ' True
' Vacía o nula:
Dim x As String = ""
Console.WriteLine(String.IsNullOrEmpty(x)) ' True
Console.WriteLine(String.IsNullOrWhiteSpace(" ")) ' True
' Invertir:
Dim inv = StrReverse("abc") ' "cba"StartsWith, EndsWith y Contains verifican contenido. IsNullOrWhiteSpace es la comprobación más segura para entradas del usuario.
String.Format
Dim nombre = "Ana"
Dim edad = 30
' Format con posiciones:
Dim msg = String.Format("{0} tiene {1} años", nombre, edad)
' Reutilizar la misma posición:
Dim r = String.Format("{0} + {0} = {1}", 5, 10) ' "5 + 5 = 10"
' Formato numérico:
Console.WriteLine(String.Format("{0:F2}", 3.14159)) ' "3.14"
Console.WriteLine(String.Format("{0:D5}", 42)) ' "00042"
Console.WriteLine(String.Format("{0:X}", 255)) ' "FF"String.Format sustituye los marcadores {0}, {1} por los argumentos. Los códigos F2, D5 y X formatean números.
Pad, Trim y Remove
Dim s = " Hola "
Console.WriteLine(s.Trim()) ' "Hola"
Console.WriteLine(s.TrimStart()) ' "Hola "
Console.WriteLine(s.TrimEnd()) ' " Hola"
' Rellenar hasta un tamaño:
Console.WriteLine("42".PadLeft(5, "0"c)) ' "00042"
Console.WriteLine("Hi".PadRight(6, "."c)) ' "Hi...."
' Eliminar parte:
Console.WriteLine("Hola Mundo".Remove(4)) ' "Hola"
Console.WriteLine("Hola Mundo".Remove(4, 3)) ' "Holando"Trim elimina espacios en los extremos. PadLeft/PadRight rellenan hasta un tamaño. Remove borra a partir de un índice.
Expresiones regulares
Imports System.Text.RegularExpressions
Dim texto = "Contacto: 912345678 o 923456789"
' Encontrar todas las coincidencias:
Dim matches = Regex.Matches(texto, "\d{9}")
For Each m As Match In matches
Console.WriteLine(m.Value)
Next
' Sustituir:
Dim limpio = Regex.Replace(texto, "\d", "*")
' Validar:
Dim ok = Regex.IsMatch("ana@mail.com",
"^[\w.]+@[\w.]+\.\w+$")La clase Regex hace búsqueda avanzada de patrones. Matches encuentra todas las ocurrencias, Replace sustituye e IsMatch valida.
Classes e OOP
Clase y constructor
Public Class Persona
Public Property Nombre As String
Public Property Edad As Integer
' Constructor:
Public Sub New(nombre As String, edad As Integer)
Me.Nombre = nombre
Me.Edad = edad
End Sub
Public Function Saludo() As String
Return $"Hola, soy {Nombre}"
End Function
End Class
Dim p As New Persona("Ana", 30)Una clase se define con Class...End Class. El constructor es el método Sub New y Me se refiere a la instancia actual.
NotInheritable y Shadows
' Clase sellada (no puede heredarse):
Public NotInheritable Class Utilitario
Public Shared Function Version() As String
Return "1.0"
End Function
End Class
' Shadows: oculta el miembro de la base:
Public Class Base
Public Function Info() As String
Return "Base"
End Function
End Class
Public Class Hija
Inherits Base
Public Shadows Function Info() As String
Return "Hija"
End Function
End ClassNotInheritable impide la herencia (clase sellada). Shadows oculta un miembro heredado con uno nuevo del mismo nombre, sin polimorfismo.
Enum
Public Enum DiaSemana
Lunes = 1
Martes
Miercoles
Jueves
Viernes
Sábado
Domingo
End Enum
Dim dia = DiaSemana.Viernes
Console.WriteLine(dia) ' Viernes
Console.WriteLine(CInt(dia)) ' 5
' Convertir desde número:
Dim d = CType(3, DiaSemana) ' MiercolesUn Enum define un conjunto de constantes con nombre. Los valores son enteros por defecto (empezando en 0 o en el valor indicado). CType convierte números en enum.
Modificadores de acceso
Public Class Cuenta
Public Saldo As Decimal ' accesible en todas partes
Private _código As String ' solo dentro de la clase
Protected Titular As String ' clase y derivadas
Friend Banco As String ' solo en el mismo assembly
Public Sub New()
_código = GenerarCodigo() ' accede al privado
End Sub
Private Function GenerarCodigo() As String
Return Guid.NewGuid().ToString()
End Function
End ClassPublic es accesible en todas partes; Private solo en la clase; Protected en la clase y derivadas; Friend solo dentro del mismo assembly.
Interfaces
Public Interface INadador
Sub Nadar()
End Interface
Public Interface ICorredor
Sub Correr()
End Interface
Public Class Atleta
Implements INadador, ICorredor
Public Sub Nadar() Implements INadador.Nadar
Console.WriteLine("Nadando")
End Sub
Public Sub Correr() Implements ICorredor.Correr
Console.WriteLine("Corriendo")
End Sub
End ClassUna Interface define un contrato sin implementación. La clase usa Implements para adoptarla y vincula cada método con Implements Nombre.Miembro.
Structure (tipo por valor)
Public Structure Punto
Public X As Double
Public Y As Double
Public Sub New(x As Double, y As Double)
Me.X = x
Me.Y = y
End Sub
Public Function Distancia() As Double
Return Math.Sqrt(X ^ 2 + Y ^ 2)
End Function
End Structure
Dim p As New Punto(3, 4)
Console.WriteLine(p.Distancia()) ' 5Una Structure es un tipo por valor (guardado en la stack), ideal para datos pequeños. A diferencia de las clases, no soporta herencia y la copia se hace por valor.
Herencia
Public Class Animal
Public Property Nombre As String
Public Overridable Function Sonido() As String
Return "..."
End Function
End Class
Public Class Perro
Inherits Animal
Public Overrides Function Sonido() As String
Return "¡Guau guau!"
End Function
End Class
Dim p As New Perro()
Console.WriteLine(p.Sonido()) ' ¡Guau guau!Inherits crea una clase derivada. Overridable permite redefinir un método en la base; Overrides proporciona la nueva implementación en la derivada.
Shared (estático)
Public Class Contador
Public Shared Total As Integer = 0
Public Sub New()
Total += 1
End Sub
Public Shared Function ObtenerTotal() As Integer
Return Total
End Function
End Class
Dim a As New Contador()
Dim b As New Contador()
Console.WriteLine(Contador.Total) ' 2Los miembros Shared pertenecen a la clase y no a la instancia. Se accede a ellos por el nombre de la clase (Contador.Total) y se comparten entre todos los objetos.
Genéricos
' Clase genérica:
Public Class Caja(Of T)
Public Property Valor As T
Public Sub New(valor As T)
Me.Valor = valor
End Sub
End Class
Dim c1 As New Caja(Of Integer)(42)
Dim c2 As New Caja(Of String)("hola")
Console.WriteLine(c1.Valor) ' 42
Console.WriteLine(c2.Valor) ' holaLos genéricos usan (Of T) para crear tipos reutilizables con cualquier tipo de dato. El mismo código funciona para Integer, String, etc.
MustInherit y MustOverride
' Clase abstracta (no puede instanciarse):
Public MustInherit Class Forma
Public MustOverride Function Area() As Double
Public Function Describir() As String
Return $"Área: {Area()}"
End Function
End Class
Public Class Círculo
Inherits Forma
Public Radio As Double
Public Overrides Function Area() As Double
Return Math.PI * Radio ^ 2
End Function
End ClassMustInherit hace la clase abstracta (no instanciable). MustOverride declara un método sin cuerpo que las derivadas están obligadas a implementar.
Overrides y Overloads
Public Class Calculadora
' Overloads: mismo nombre, parámetros diferentes
Public Overloads Function Sumar(a As Integer, b As Integer) As Integer
Return a + b
End Function
Public Overloads Function Sumar(a As Double, b As Double) As Double
Return a + b
End Function
Public Overloads Function Sumar(nums() As Integer) As Integer
Return nums.Sum()
End Function
End ClassOverloads permite varios métodos con el mismo nombre pero firmas diferentes (nº o tipo de parámetros). El compilador elige el correcto según la llamada.
Restricciones genéricas
' T debe ser una clase (tipo por referencia):
Public Class Repo(Of T As Class)
End Class
' T debe implementar una interfaz:
Public Class Ordenador(Of T As IComparable(Of T))
Public Function Max(a As T, b As T) As T
Return If(a.CompareTo(b) >= 0, a, b)
End Function
End Class
' T debe tener constructor sin parámetros:
Public Class Fabrica(Of T As New)
Public Function Crear() As T
Return New T()
End Function
End ClassLas restricciones (As Class, As New, As IComparable) limitan los tipos aceptados por un genérico, permitiendo usar métodos específicos con seguridad.
Avançado
Async / Await
Async Function DescargarAsync(url As String) As Task(Of String)
Using client As New HttpClient()
Dim resultado = Await client.GetStringAsync(url)
Return resultado
End Using
End Function
' Llamar:
Async Function EjecutarAsync() As Task
Dim datos = Await DescargarAsync("https://api.ejemplo.com")
Console.WriteLine(datos)
End FunctionLos métodos Async devuelven Task o Task(Of T). El Await pausa sin bloquear el hilo, liberando la interfaz para otras tareas.
Eventos
Public Class Termometro
Public Event AlCambiar(sender As Object, temp As Double)
Private _temp As Double
Public Property Temperatura As Double
Get
Return _temp
End Get
Set(value As Double)
_temp = value
RaiseEvent AlCambiar(Me, value)
End Set
End Property
End ClassUn Event notifica a los suscriptores cuando algo ocurre. RaiseEvent dispara el evento. Es el patrón usado en interfaces gráficas y observadores.
Reflexión
Imports System.Reflection
Dim tipo = GetType(Persona)
Console.WriteLine(tipo.Name) ' "Persona"
Console.WriteLine(tipo.FullName)
' Listar métodos:
For Each m As MethodInfo In tipo.GetMethods()
Console.WriteLine(m.Name)
Next
' Listar propiedades:
For Each p In tipo.GetProperties()
Console.WriteLine($"{p.Name}: {p.PropertyType.Name}")
NextLa reflexión (GetType, GetMethods, GetProperties) inspecciona tipos en tiempo de ejecución. La usan serializadores y frameworks.
Task y Task.Run
' Ejecutar trabajo en segundo plano:
Async Function ProcesarAsync() As Task(Of Integer)
Dim resultado = Await Task.Run(Function()
Threading.Thread.Sleep(1000)
Return 42
End Function)
Return resultado
End Function
' Varias tareas en paralelo:
Dim t1 = DescargarAsync("url1")
Dim t2 = DescargarAsync("url2")
Await Task.WhenAll(t1, t2)Task.Run ejecuta código en un hilo del pool. Task.WhenAll espera varias tareas en paralelo, mejorando el rendimiento en operaciones independientes.
AddHandler y Handles
Dim t As New Termometro()
' Suscribirse en tiempo de ejecución:
AddHandler t.AlCambiar,
Sub(sender, temp) Console.WriteLine($"Temp: {temp}")
t.Temperatura = 36.5 ' imprime "Temp: 36.5"
' O con Handles (en clase):
Private Sub AlCambiarHandler(sender As Object, temp As Double) _
Handles t.AlCambiar
Console.WriteLine($"Cambió a {temp}")
End Sub
' Eliminar:
RemoveHandler t.AlCambiar, AddressOf AlCambiarHandlerAddHandler suscribe un evento en tiempo de ejecución; Handles lo vincula en tiempo de compilación. RemoveHandler cancela la suscripción.
Atributos
<Obsolete("Use NuevoMetodo en lugar de este")>
Public Sub MetodoAntiguo()
End Sub
' Atributo con parámetros:
<DebuggerDisplay("Nombre={Nombre}, Edad={Edad}")>
Public Class Persona
Public Property Nombre As String
Public Property Edad As Integer
End Class
' Atributo de assembly:
<Assembly: AssemblyVersion("1.0.0.0")>Los atributos (entre < >) añaden metadatos al código. Obsolete marca código obsoleto; DebuggerDisplay personaliza la depuración.
Delegates
' Declarar un delegate:
Public Delegate Function Operacion(a As Integer, b As Integer) As Integer
Function Sumar(a As Integer, b As Integer) As Integer
Return a + b
End Function
' Usar:
Dim op As Operacion = AddressOf Sumar
Dim r = op(3, 4) ' 7
' Apuntar a una lambda:
Dim op2 As Operacion = Function(a, b) a * b
Console.WriteLine(op2(3, 4)) ' 12Un Delegate es un tipo que referencia un método. AddressOf lo vincula a un método existente. Es la base de eventos y callbacks en VB.NET.
Tipos Nullable
' Tipo por valor que puede ser Nothing: Dim x As Integer? = Nothing Console.WriteLine(x.HasValue) ' False Console.WriteLine(x.GetValueOrDefault()) ' 0 x = 42 Console.WriteLine(x.HasValue) ' True Console.WriteLine(x.Value) ' 42 ' Operador de coalescencia: Dim y As Integer? = Nothing Dim resultado = If(y, 0) ' 0 si y es Nothing
Un tipo Nullable (Integer?) puede contener Nothing además del valor normal. HasValue y Value verifican y obtienen el valor con seguridad.
Operadores Nothing e Is
Dim s As String = Nothing
' Comparar con Nothing:
If s Is Nothing Then
Console.WriteLine("sin valor")
End If
If s IsNot Nothing Then
Console.WriteLine(s.Length)
End If
' Referencia igual:
Dim a As New Object()
Dim b = a
Console.WriteLine(a Is b) ' True (mismo objeto)
Console.WriteLine(a IsNot b) ' FalseUsa Is Nothing e IsNot Nothing para verificar referencias nulas. Is compara identidad de objeto, no igualdad de valor.
Action y Func
' Func: devuelve valor (el último tipo es el retorno):
Dim doble As Func(Of Integer, Integer) = Function(x) x * 2
Console.WriteLine(doble(5)) ' 10
Dim suma As Func(Of Integer, Integer, Integer) =
Function(a, b) a + b
' Action: no devuelve valor:
Dim imprimir As Action(Of String) = Sub(msg) Console.WriteLine(msg)
imprimir("Hola")
' Predicate: devuelve Boolean:
Dim par As Predicate(Of Integer) = Function(n) n Mod 2 = 0
Console.WriteLine(par(4)) ' TrueFunc y Action son delegates listos: Func devuelve un valor, Action no. Evitan declarar delegates personalizados para casos simples.
TypeOf y CType
Dim obj As Object = "Hola"
' Verificar el tipo:
If TypeOf obj Is String Then
Console.WriteLine("Es una string")
End If
' Convertir (lanza excepción si falla):
Dim s = CType(obj, String)
' Conversión segura (devuelve Nothing si falla):
Dim n = TryCast(obj, Integer) ' Nothing
If n IsNot Nothing Then
Console.WriteLine(n)
End IfTypeOf...Is verifica el tipo en tiempo de ejecución. CType convierte (lanza excepción si es imposible); TryCast devuelve Nothing en vez de fallar.
NameOf e interpolación
Public Sub Validar(nombre As String)
If String.IsNullOrEmpty(nombre) Then
' NameOf devuelve el nombre del parámetro:
Throw New ArgumentException("Inválido", NameOf(nombre))
End If
End Sub
Console.WriteLine(NameOf(Validar)) ' "Validar"
Console.WriteLine(NameOf(Persona.Nombre)) ' "Nombre"NameOf devuelve el nombre de un símbolo como string, en tiempo de compilación. Es útil en mensajes de error y notificaciones, evitando strings escritas a mano.
Controlo de Fluxo
If / ElseIf / Else
Dim edad = 20
If edad >= 18 Then
Console.WriteLine("Adulto")
ElseIf edad >= 12 Then
Console.WriteLine("Adolescente")
Else
Console.WriteLine("Niño")
End If
' Single-line (sin End If):
If edad > 0 Then Console.WriteLine("positivo")El bloque If...Then...End If termina siempre con End If. En instrucciones de una línea el End If es opcional.
While y Do Loop
Dim x = 5
' While (verifica antes):
While x > 0
x -= 1
End While
' Do Until (repite hasta ser verdadero):
x = 0
Do Until x = 10
x += 1
Loop
' Do While (repite mientras sea verdadero):
Do While x > 0
x -= 1
LoopWhile...End While repite mientras la condición sea verdadera. Do Until repite hasta que la condición sea verdadera; Do While repite mientras lo sea.
Throw y excepciones personalizadas
Sub DefinirEdad(edad As Integer)
If edad < 0 Then
Throw New ArgumentException("Edad inválida")
End If
End Sub
' Excepción personalizada:
Public Class SaldoInsuficienteException
Inherits Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
Throw New SaldoInsuficienteException("Sin fondos")Throw lanza una excepción. Puedes crear excepciones propias heredando de Exception y llamando a MyBase.New para pasar el mensaje.
Select Case
Dim dia = 3
Select Case dia
Case 1
Console.WriteLine("Lunes")
Case 2, 3
Console.WriteLine("Martes o Miércoles")
Case 4 To 6
Console.WriteLine("Mitad de semana")
Case Is >= 7
Console.WriteLine("Fin de semana")
Case Else
Console.WriteLine("Inválido")
End SelectEl Select Case es el switch de VB. Soporta valores únicos, listas (Case 2, 3), rangos (Case 4 To 6) y condiciones con Is.
Do con condición al final
Dim n = 0
' La condición se prueba DESPUÉS (ejecuta al menos 1 vez):
Do
n += 1
Console.WriteLine(n)
Loop Until n >= 5
Do
n -= 1
Loop While n > 0Cuando la condición viene después del Loop, el bloque se ejecuta siempre al menos una vez. Es útil para menús y validaciones de entrada.
When (filtro de excepción)
Try
Dim n = CInt(Console.ReadLine())
Catch ex As FormatException When ex.Message.Contains("input")
Console.WriteLine("Formato específico")
Catch ex As Exception When TypeOf ex Is OverflowException
Console.WriteLine("Valor demasiado grande")
Catch ex As Exception
Console.WriteLine("Otro error")
End TryLa cláusula When filtra excepciones por una condición booleana. Solo se ejecuta el Catch cuyo filtro devuelva True.
For ... Next
' Cuenta creciente:
For i As Integer = 1 To 10
Console.WriteLine(i)
Next
' Cuenta decreciente con Step:
For i = 10 To 1 Step -1
Console.WriteLine(i)
Next
' Paso de 2 en 2:
For i = 0 To 20 Step 2
Console.WriteLine(i)
NextEl bucle For...Next repite un bloque un número definido de veces. El Step define el incremento (puede ser negativo para contar hacia atrás).
Exit y Continue
For i = 1 To 10
If i = 3 Then Continue For ' salta al siguiente
If i = 8 Then Exit For ' sale del bucle
Console.WriteLine(i)
Next
' Imprime: 1 2 4 5 6 7
While True
Dim cmd = Console.ReadLine()
If cmd = "salir" Then Exit While
End WhileContinue For salta a la siguiente iteración; Exit For termina el bucle inmediatamente. También existen Exit While, Exit Do y Exit Sub.
Using (recursos automáticos)
Imports System.IO
Using reader As New StreamReader("datos.txt")
Dim linea = reader.ReadLine()
Console.WriteLine(linea)
End Using
' reader se cierra/libera automáticamente aquí
' Varios recursos:
Using fs = File.OpenRead("a.txt"),
sr = New StreamReader(fs)
Console.WriteLine(sr.ReadToEnd())
End UsingEl bloque Using garantiza que objetos con recursos (archivos, conexiones) se liberan automáticamente al final, incluso si ocurre una excepción.
For Each
Dim frutas = {"Manzana", "Pera", "Uva"}
For Each fruta In frutas
Console.WriteLine(fruta)
Next
' Con índice (si necesitas la posición):
For i = 0 To frutas.Length - 1
Console.WriteLine($"{i}: {frutas(i)}")
NextEl For Each recorre cada elemento de una colección sin necesidad de índice. Usa el For normal cuando necesites la posición del elemento.
Try / Catch / Finally
Try
Dim r = 10 \ 0
Catch ex As DivideByZeroException
Console.WriteLine("¡División por cero!")
Catch ex As Exception
Console.WriteLine($"Error: {ex.Message}")
Finally
Console.WriteLine("Se ejecuta siempre")
End TryEl bloque Try protege código que puede fallar. El Catch captura la excepción (puede haber varios, del más específico al general) y el Finally se ejecuta siempre.
With (acceso a miembros)
Dim p As New Persona()
With p
.Nombre = "Ana"
.Edad = 30
.Email = "ana@mail.com"
End With
' Equivalente a:
' p.Nombre = "Ana"
' p.Edad = 30
' p.Email = "ana@mail.com"
Console.WriteLine(p.Nombre)El bloque With evita repetir el nombre del objeto al definir varias propiedades. El punto . se refiere al objeto del With.
Coleções e LINQ
Arrays
' Declarar e inicializar:
Dim nums() As Integer = {1, 2, 3, 4, 5}
Dim nombres = {"Ana", "Ray", "Mia"}
' Acceso (el índice empieza en 0):
Console.WriteLine(nums(0)) ' 1
nums(0) = 10
' Tamaño:
Console.WriteLine(nums.Length) ' 5Un array tiene tamaño fijo e índice que empieza en 0. Length devuelve el número de elementos. Los valores se definen entre llaves {}.
List(Of T)
Dim lista As New List(Of String)
lista.Add("Ana")
lista.Add("Ray")
lista.Insert(0, "Mia") ' inserta al inicio
lista.Remove("Ana") ' elimina por valor
lista.RemoveAt(0) ' elimina por índice
Console.WriteLine(lista.Count) ' 1
Console.WriteLine(lista.Contains("Ray")) ' True
Console.WriteLine(lista(0)) ' RayLa List(Of T) es un array dinámico que crece automáticamente. Tiene Add, Insert, Remove y la propiedad Count.
HashSet(Of T)
Dim conjunto As New HashSet(Of Integer) From {1, 2, 3}
conjunto.Add(3) ' ignorado (ya existe)
conjunto.Add(4)
Console.WriteLine(conjunto.Count) ' 4
Console.WriteLine(conjunto.Contains(2)) ' True
' Operaciones de conjuntos:
Dim a As New HashSet(Of Integer) From {1, 2, 3}
Dim b As New HashSet(Of Integer) From {2, 3, 4}
a.IntersectWith(b) ' a = {2, 3}El HashSet guarda valores únicos sin duplicados y con verificación rápida de existencia. Tiene operaciones como IntersectWith, UnionWith y ExceptWith.
ReDim y Preserve
Dim nums(4) As Integer ' 5 elementos (0 a 4) ' Redimensionar (pierde los datos): ReDim nums(9) ' Redimensionar manteniendo los datos: Dim lista(2) As String lista(0) = "A" lista(1) = "B" ReDim Preserve lista(5) ' mantiene A y B Console.WriteLine(lista.Length) ' 6
ReDim cambia el tamaño del array. Sin Preserve los datos se pierden; con Preserve se mantienen los elementos existentes.
List - búsqueda y ordenación
Dim nums As New List(Of Integer) From {5, 2, 8, 1, 9}
nums.Sort() ' ordena
nums.Reverse() ' invierte
' Encontrar con predicado:
Dim mayor5 = nums.Find(Function(n) n > 5)
Dim todos = nums.FindAll(Function(n) n Mod 2 = 0)
' Eliminar con condición:
nums.RemoveAll(Function(n) n < 3)
Dim existe = nums.Exists(Function(n) n = 8)Find devuelve el primer elemento que satisface el predicado; FindAll devuelve todos. RemoveAll y Exists también reciben una lambda.
LINQ - sintaxis de consulta
Dim nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim pares = From n In nums
Where n Mod 2 = 0
Order By n Descending
Select n * 2
For Each r In pares
Console.WriteLine(r)
NextLa sintaxis de consulta LINQ parece SQL: From define la fuente, Where filtra, Order By ordena y Select proyecta el resultado.
Operaciones con arrays
Dim nums = {5, 2, 8, 1, 9}
Array.Sort(nums) ' ordena: 1 2 5 8 9
Array.Reverse(nums) ' invierte: 9 8 5 2 1
Dim pos = Array.IndexOf(nums, 5) ' posición de 5
Dim existe = nums.Contains(8) ' True
Dim total = nums.Sum()
Dim mayor = nums.Max()
Dim media = nums.Average()La clase Array ofrece Sort, Reverse e IndexOf. Los métodos de extensión LINQ como Sum, Max y Average hacen cálculos rápidos.
Dictionary(Of TKey, TValue)
Dim edades As New Dictionary(Of String, Integer)
edades("Ana") = 30
edades.Add("Ray", 25)
edades("Mia") = 22
Console.WriteLine(edades("Ana")) ' 30
Console.WriteLine(edades.ContainsKey("Ray")) ' True
Console.WriteLine(edades.Count) ' 3
' Acceso seguro:
Dim valor As Integer
If edades.TryGetValue("Zé", valor) Then
Console.WriteLine(valor)
End IfEl Dictionary guarda pares clave/valor con acceso rápido por la clave. TryGetValue evita una excepción cuando la clave no existe.
LINQ - sintaxis de método
Dim nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim r = nums.Where(Function(n) n > 5) _
.OrderByDescending(Function(n) n) _
.Take(3) _
.ToList()
' Otros métodos útiles:
Dim suma = nums.Sum()
Dim pares = nums.Count(Function(n) n Mod 2 = 0)
Dim primero = nums.First(Function(n) n > 3)La sintaxis de método encadena operadores como Where, OrderBy y Take usando lambdas. Sum, Count y First hacen agregaciones.
Arrays multidimensionales
' Matriz 2D (3 filas x 3 columnas):
Dim matriz(,) As Integer = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
Console.WriteLine(matriz(1, 2)) ' 6
' Recorrer:
For i = 0 To matriz.GetLength(0) - 1
For j = 0 To matriz.GetLength(1) - 1
Console.Write(matriz(i, j) & " ")
Next
Console.WriteLine()
NextLos arrays multidimensionales usan coma en la declaración: (,) para 2D. GetLength(0) da el nº de filas y GetLength(1) el nº de columnas.
Recorrer Dictionary
Dim edades As New Dictionary(Of String, Integer) From {
{"Ana", 30},
{"Ray", 25},
{"Mia", 22}
}
For Each par In edades
Console.WriteLine($"{par.Key}: {par.Value}")
Next
' Solo las claves / solo los valores:
For Each nombre In edades.Keys
Console.WriteLine(nombre)
NextAl recorrer un Dictionary cada elemento es un par con Key y Value. Las propiedades Keys y Values dan acceso por separado.
LINQ - proyección y agrupación
Dim personas = GetPersonas()
' Proyección (Select):
Dim nombres = personas.Select(Function(p) p.Nombre).ToList()
' Agrupación:
Dim porCiudad = From p In personas
Group By p.Ciudad Into Grupo = Group
Select Ciudad, Total = Grupo.Count()
' Distintos:
Dim ciudades = personas.Select(Function(p) p.Ciudad).Distinct()Select transforma cada elemento. Group By...Into Group agrupa por una clave y Distinct elimina duplicados del resultado.
Entrada/Saída e Ficheiros
Entrada y salida en la consola
' Salida:
Console.WriteLine("Con nueva línea")
Console.Write("Sin nueva línea")
Console.WriteLine($"Valor: {42}")
' Entrada:
Console.Write("Nombre: ")
Dim nombre = Console.ReadLine()
' Leer un número:
Console.Write("Edad: ")
Dim edad = CInt(Console.ReadLine())
' Limpiar y colores:
Console.ForegroundColor = ConsoleColor.Green
Console.WriteLine("¡Éxito!")
Console.ResetColor()Console.WriteLine escribe con nueva línea; ReadLine lee una línea como string. ForegroundColor cambia el color del texto en la consola.
Rutas (Path)
Imports System.IO
Dim ruta = "C:\datos\informe.txt"
Console.WriteLine(Path.GetFileName(ruta)) ' "informe.txt"
Console.WriteLine(Path.GetExtension(ruta)) ' ".txt"
Console.WriteLine(Path.GetFileNameWithoutExtension(ruta))
Console.WriteLine(Path.GetDirectoryName(ruta))
' Unir rutas con seguridad:
Dim nueva = Path.Combine("C:\datos", "sub", "f.txt")
' Archivo temporal:
Dim temp = Path.GetTempFileName()La clase Path manipula rutas sin errores de separadores. Path.Combine une partes con seguridad y GetExtension obtiene la extensión.
Acceder a base de datos
Imports System.Data.SqlClient
Dim connStr = "Server=.;Database=Tienda;Trusted_Connection=True;"
Using conn As New SqlConnection(connStr)
conn.Open()
Using cmd As New SqlCommand("SELECT Nombre FROM Cliente", conn)
Using reader = cmd.ExecuteReader()
While reader.Read()
Console.WriteLine(reader("Nombre"))
End While
End Using
End Using
End UsingAcceso ADO.NET: SqlConnection conecta a la base de datos, SqlCommand ejecuta la query y ExecuteReader recorre los resultados. Usa siempre Using.
Escribir archivos
Imports System.IO
' Escribir todo de una vez:
File.WriteAllText("f.txt", "Hola Mundo")
' Varias líneas:
File.WriteAllLines("f.txt", {"L1", "L2", "L3"})
' Añadir al final:
File.AppendAllText("log.txt", "nueva línea" & vbCrLf)
' Con StreamWriter (más control):
Using sw As New StreamWriter("f.txt")
sw.WriteLine("Línea 1")
sw.WriteLine("Línea 2")
End UsingFile.WriteAllText y WriteAllLines crean/sobrescriben archivos. AppendAllText añade al final. El StreamWriter da más control en escritura progresiva.
Listar archivos y carpetas
Imports System.IO
' Listar archivos:
For Each f In Directory.GetFiles("C:\datos")
Console.WriteLine(f)
Next
' Con filtro y recursión:
Dim txts = Directory.GetFiles("C:\datos", "*.txt",
SearchOption.AllDirectories)
' Listar carpetas:
For Each d In Directory.GetDirectories("C:\datos")
Console.WriteLine(d)
Next
' Versión lazy (memoria eficiente):
For Each f In Directory.EnumerateFiles("C:\datos", "*.log")
Console.WriteLine(f)
NextGetFiles y GetDirectories listan contenidos. El filtro *.txt selecciona por extensión y SearchOption.AllDirectories búsqueda recursivamente.
Parámetros SQL (anti-inyección)
Using conn As New SqlConnection(connStr)
conn.Open()
Dim sql = "SELECT * FROM Cliente WHERE Edad > @edad"
Using cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@edad", 18)
Dim count = CInt(cmd.ExecuteScalar())
Console.WriteLine($"Mayores: {count}")
End Using
End Using
' Insertar con parámetros:
Dim ins = "INSERT INTO Cliente (Nombre) VALUES (@nombre)"Usa siempre parámetros (@edad) en vez de concatenar strings en las queries. Esto previene la inyección de SQL. ExecuteScalar devuelve un único valor.
Leer archivos
Imports System.IO
' Leer todo como texto:
Dim contenido = File.ReadAllText("f.txt")
' Leer como array de líneas:
Dim lineas = File.ReadAllLines("f.txt")
For Each linea In lineas
Console.WriteLine(linea)
Next
' Con StreamReader (línea a línea):
Using sr As New StreamReader("f.txt")
Dim l As String
While (InlineAssignHelper(l, sr.ReadLine())) IsNot Nothing
Console.WriteLine(l)
End While
End UsingReadAllText devuelve el archivo entero; ReadAllLines devuelve un array de líneas. El StreamReader es eficiente para archivos grandes, leyendo línea a línea.
Serialización JSON
Imports System.Text.Json
Public Class Persona
Public Property Nombre As String
Public Property Edad As Integer
End Class
' Serializar:
Dim p As New Persona With {.Nombre = "Ana", .Edad = 30}
Dim json = JsonSerializer.Serialize(p)
' Deserializar:
Dim p2 = JsonSerializer.Deserialize(Of Persona)(json)
Console.WriteLine(p2.Nombre) ' AnaJsonSerializer.Serialize convierte un objeto en JSON; Deserialize(Of T) hace lo inverso. Está incluido en System.Text.Json en el .NET moderno.
Verificar y gestionar archivos
Imports System.IO
' Verificar existencia:
If File.Exists("f.txt") Then
Console.WriteLine("Existe")
End If
If Directory.Exists("carpeta") Then
Console.WriteLine("La carpeta existe")
End If
' Crear carpeta:
Directory.CreateDirectory("datos/logs")
' Borrar:
File.Delete("temp.txt")
' Mover / copiar:
File.Copy("a.txt", "b.txt", overwrite:=True)
File.Move("a.txt", "c.txt")File.Exists y Directory.Exists verifican existencia. CreateDirectory crea carpetas; Delete, Copy y Move gestionan archivos.
Serialización XML
Imports System.Xml.Serialization
<Serializable()>
Public Class Producto
Public Property Nombre As String
Public Property Precio As Decimal
End Class
Dim serializer As New XmlSerializer(GetType(Producto))
Using sw As New StreamWriter("producto.xml")
serializer.Serialize(sw, New Producto With {.Nombre = "Libro", .Precio = 9.9})
End UsingEl XmlSerializer convierte objetos en XML y viceversa. El tipo debe ser serializable y tener un constructor sin parámetros. Usa Serialize y Deserialize.
Tipos e Recursos Extra
Tipos anónimos
Dim persona = New With {
.Nombre = "Ana",
.Edad = 30
}
Console.WriteLine(persona.Nombre) ' Ana
Console.WriteLine(persona.Edad) ' 30
' En LINQ:
Dim resultados = From n In {1, 2, 3, 4}
Select New With {.Numero = n, .Doble = n * 2}Los tipos anónimos (New With { }) crean objetos sin definir una clase. Son útiles en proyecciones LINQ para resultados temporales con propiedades con nombre.
Math (matemáticas)
Console.WriteLine(Math.PI) ' 3.14159... Console.WriteLine(Math.E) Console.WriteLine(Math.Abs(-5)) ' 5 Console.WriteLine(Math.Max(3, 7)) ' 7 Console.WriteLine(Math.Min(3, 7)) ' 3 Console.WriteLine(Math.Pow(2, 10)) ' 1024 Console.WriteLine(Math.Sqrt(16)) ' 4 Console.WriteLine(Math.Round(3.7)) ' 4 Console.WriteLine(Math.Floor(3.7)) ' 3 Console.WriteLine(Math.Ceiling(3.2)) ' 4
La clase Math tiene constantes (PI, E) y funciones como Abs, Pow, Sqrt, Round, Floor y Ceiling.
Colecciones especializadas
Imports System.Collections.Generic
' Queue (FIFO - primero en entrar, primero en salir):
Dim cola As New Queue(Of String)
cola.Enqueue("A")
cola.Enqueue("B")
Console.WriteLine(cola.Dequeue()) ' A
' Stack (LIFO - último en entrar, primero en salir):
Dim pila As New Stack(Of Integer)
pila.Push(1)
pila.Push(2)
Console.WriteLine(pila.Pop()) ' 2Queue es una cola (FIFO) con Enqueue/Dequeue. Stack es una pila (LIFO) con Push/Pop. Elige según el orden necesario.
Tuplas
' Tupla con nombres:
Dim persona = (Nombre:="Ana", Edad:=30)
Console.WriteLine(persona.Nombre) ' Ana
Console.WriteLine(persona.Edad) ' 30
' Devolver varios valores de una función:
Function Dividir(a As Integer, b As Integer) As (Cociente As Integer, Resto As Integer)
Return (a \ b, a Mod b)
End Function
Dim r = Dividir(10, 3)
Console.WriteLine($"{r.Cociente} resto {r.Resto}") ' 3 resto 1Las tuplas agrupan varios valores sin crear una clase. Con nombres (Nombre:=) los campos quedan legibles. Son ideales para devolver múltiples valores de una función.
Random (aleatorios)
Dim rnd As New Random() ' Entero aleatorio: Dim n = rnd.Next() ' 0 hasta Integer.MaxValue Dim dado = rnd.Next(1, 7) ' 1 a 6 ' Double entre 0.0 y 1.0: Dim f = rnd.NextDouble() ' Rellenar array de bytes: Dim bytes(15) As Byte rnd.NextBytes(bytes) ' Compartir una instancia (evita repetición): Shared ReadOnly Rnd As New Random()
La clase Random genera números aleatorios. Next(min, max) devuelve un entero en el intervalo (máx exclusivo). Reutiliza la instancia para evitar valores repetidos.
Conversiones de colección
Dim lista As New List(Of Integer) From {1, 2, 3}
' List a Array:
Dim arr = lista.ToArray()
' Array a List:
Dim lista2 = arr.ToList()
' List a Dictionary:
Dim personas = GetPersonas()
Dim dict = personas.ToDictionary(
Function(p) p.Id,
Function(p) p.Nombre)
' Filtrar a nueva lista:
Dim pares = lista.Where(Function(n) n Mod 2 = 0).ToList()ToArray y ToList convierten entre colecciones. ToDictionary crea un diccionario a partir de una lista usando funciones para clave y valor.
Colecciones inmutables
Imports System.Collections.Immutable
Dim lista = ImmutableList.CreateRange({1, 2, 3})
' "Cambiar" devuelve una nueva lista:
Dim lista2 = lista.Add(4)
Console.WriteLine(lista.Count) ' 3 (sin cambios)
Console.WriteLine(lista2.Count) ' 4
Dim dict = ImmutableDictionary(Of String, Integer).Empty
Dim dict2 = dict.Add("Ana", 30)Las colecciones inmutables (ImmutableList, ImmutableDictionary) nunca cambian: cada operación devuelve una nueva colección. Son seguras en código concurrente.
Guid (identificador único)
' Generar un GUID:
Dim id = Guid.NewGuid()
Console.WriteLine(id) ' ej: 3f2a...-...-...
' Como string sin guiones:
Dim s = id.ToString("N")
' GUID vacío:
Dim vacio = Guid.Empty
Console.WriteLine(id = Guid.Empty) ' False
' Convertir desde string:
Dim g = Guid.Parse("3f2a1b...")Guid.NewGuid() genera un identificador único global de 128 bits. Se usa como clave primaria y para nombres únicos. Guid.Empty es el valor nulo.
Conversiones avanzadas
' Enum a string y viceversa:
Dim dia = DiaSemana.Viernes
Dim nombre = dia.ToString() ' "Viernes"
Dim vuelta = [Enum].Parse(GetType(DiaSemana), "Viernes")
' Array de bytes a Base64:
Dim bytes = {1, 2, 3, 4}
Dim b64 = Convert.ToBase64String(bytes)
Dim orig = Convert.FromBase64String(b64)
' Objeto a string:
Dim o As Object = 42
Dim s = Convert.ToString(o)Enum.Parse convierte texto en enum. Convert.ToBase64String codifica bytes en Base64. La clase Convert hace conversiones entre tipos diversos.
TimeSpan
' Crear un intervalo de tiempo:
Dim duracion = New TimeSpan(1, 30, 0) ' 1h 30m
Console.WriteLine(duracion.TotalMinutes) ' 90
' Métodos de fábrica:
Dim t = TimeSpan.FromHours(2)
Dim t2 = TimeSpan.FromSeconds(45)
' Diferencia entre fechas:
Dim inicio = #2024-01-01#
Dim fin = #2024-03-15#
Dim días = (fin - inicio).TotalDays
Console.WriteLine($"{días} días")TimeSpan representa una duración. TotalMinutes y TotalHours convierten a unidades. La diferencia entre dos fechas devuelve un TimeSpan.
Dicas e Boas Práticas
Inicializadores de objeto
' Sin constructor, definiendo propiedades:
Dim p As New Persona With {
.Nombre = "Ana",
.Edad = 30
}
' Colección con inicializador:
Dim personas As New List(Of Persona) From {
New Persona With {.Nombre = "Ray", .Edad = 25},
New Persona With {.Nombre = "Mia", .Edad = 22}
}
Console.WriteLine(personas.Count) ' 2El bloque With { } inicializa propiedades al crear el objeto, sin necesitar constructor. Se combina con From { } para rellenar colecciones de forma legible.
Tratamiento defensivo
Sub Procesar(lista As List(Of String))
' Validar argumentos pronto:
If lista Is Nothing Then
Throw New ArgumentNullException(NameOf(lista))
End If
If lista.Count = 0 Then Return
For Each item In lista
If String.IsNullOrWhiteSpace(item) Then Continue For
Console.WriteLine(item.Trim())
Next
End SubValida los argumentos al inicio con ArgumentNullException. Usa Return y Continue For para salir pronto de casos inválidos, manteniendo el código principal sin anidamientos.
Operador de coalescencia y Elvis
Dim nombre As String = Nothing ' If() con 2 args: primero no-Nothing: Dim mostrado = If(nombre, "Anónimo") ' Acceso seguro con ?.: Dim longitud = nombre?.Length ' Nothing (sin error) ' Combinación útil: Dim tam = nombre?.Length ?? -1 ' En VB se usa If anidado: Dim tam2 = If(nombre IsNot Nothing, nombre.Length, -1)
El operador ?. (null-conditional) solo accede al miembro si el objeto no es Nothing, evitando NullReferenceException. If(a, b) hace coalescencia.
Patrón Repository (ejemplo)
Public Interface IRepositorio(Of T)
Function Obtener(id As Integer) As T
Function Todos() As List(Of T)
Sub Guardar(entidad As T)
Sub Eliminar(id As Integer)
End Interface
Public Class ClienteRepositorio
Implements IRepositorio(Of Cliente)
Public Function Obtener(id As Integer) As Cliente _
Implements IRepositorio(Of Cliente).Obtener
' acceder a la BD...
Return New Cliente()
End Function
End ClassEl patrón Repository abstrae el acceso a datos detrás de una interfaz genérica IRepositorio(Of T). Facilita los tests y el cambio de fuente de datos sin modificar la lógica.
Patrón Dispose e IDisposable
Public Class Conexion
Implements IDisposable
Private _abierta As Boolean = True
Public Sub Cerrar()
If _abierta Then
_abierta = False
Console.WriteLine("Cerrada")
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Cerrar()
GC.SuppressFinalize(Me)
End Sub
End Class
' Uso con Using:
Using c As New Conexion()
' ...
End UsingLas clases con recursos implementan IDisposable con el método Dispose. El Using llama a Dispose automáticamente, garantizando la liberación.
Patrón Singleton
Public Class Configuracion
' Instancia única, creada de forma thread-safe:
Private Shared ReadOnly _instancia As New Lazy(Of Configuracion)(
Function() New Configuracion())
Public Shared ReadOnly Property Instancia As Configuracion
Get
Return _instancia.Value
End Get
End Property
Private Sub New() ' constructor privado
End Sub
Public Property Tema As String = "Claro"
End Class
Dim cfg = Configuracion.InstanciaEl Singleton garantiza una única instancia. El constructor Private impide la creación externa y Lazy(Of T) crea la instancia solo cuando es necesaria, de forma thread-safe.
Convenciones de nomenclatura
' Clases, métodos, propiedades: PascalCase
Public Class ClienteFidelizado
Public Property NombreCompleto As String
Public Function CalcularDescuento() As Decimal
Return 0
End Function
End Class
' Variables locales y parámetros: camelCase
Dim totalCompra As Decimal
Sub Procesar(valor As Decimal)
End Sub
' Campos privados: _camelCase
Private _saldo As DecimalUsa PascalCase para clases, métodos y propiedades; camelCase para variables locales y parámetros; prefijo _ para campos privados. Las interfaces empiezan por I.
Buenas prácticas generales
' 1. Option Strict On siempre
Option Strict On
' 2. Usar Using para recursos
Using conn = AbrirConexion()
' ...
End Using
' 3. Preferir colecciones genéricas
Dim lista As New List(Of Integer) ' no ArrayList
' 4. Async en vez de bloquear
Dim datos = Await ObtenerAsync() ' no .Result
' 5. Excepciones específicas
Try
' ...
Catch ex As IOException
' tratar
End TryActiva Option Strict On, usa Using para recursos, prefiere colecciones genéricas, usa Await en vez de bloquear y captura excepciones específicas.