Cheatsheet Visual Basic
Linguagem da Microsoft para aplicações Windows, Office e automação
Visual Basic
Basic and Structure
Program Structure
Imports System
Module Program
Sub Main(args As String())
Console.WriteLine("Hello World!")
Console.Write("Name: ")
Dim name = Console.ReadLine()
Console.WriteLine($"Hello, {name}!")
End Sub
End ModuleA VB.NET console program starts in a Module with the Sub Main method. The Imports brings in namespaces and Console writes to the screen.
Comparison and Logical Operators
Dim x = 10
' Comparison (return Boolean):
Dim r1 = x = 10 ' True
Dim r2 = x <> 5 ' True (not equal)
Dim r3 = x >= 10 ' True
' Logical:
Dim ok = r1 And r2
Dim ok2 = r1 Or r3
Dim neg = Not r1
' Short-circuit (recommended):
If x > 0 AndAlso x < 100 Then
Console.WriteLine("between 0 and 100")
End IfAndAlso and OrElse are the short-circuit versions: they stop evaluating the soon the the result is known, avoiding errors and gaining performance.
Option Strict and Option Infer
' At the top of the file:
Option Strict On ' forbids implicit conversions
Option Infer On ' allows type inference
Option Explicit On ' forces variable declaration
' With Option Strict On, this is an error:
' Dim n As Integer = "42" ' error!
' You must convert explicitly:
Dim n As Integer = CInt("42")
' Inference:
Dim list = New List(Of String)() ' inferred typeOption Strict On is good practice: it prevents automatic conversions that hide bugs. Option Infer On lets the compiler deduce the type from the value.
Variables with Dim
Dim name As String = "VB.NET" Dim age As Integer = 30 Dim active As Boolean = True Dim pi As Double = 3.14 Dim price As Decimal = 99.99D ' Type inference (Option Infer On): Dim x = 42 ' Integer Dim s = "Hello" ' String Const MAX As Integer = 100
Variables are declared with Dim. The type can be explicit (As Integer) or inferred from the value. Const creates immutable constants.
String Concatenation
Dim name = "Anna" Dim surname = "Silva" ' & operator (concatenation): Dim full = name & " " & surname ' + operator (also works): Dim s = "Hello " + name ' Join with numbers: Dim age = 30 Dim msg = name & " is " & age & " years old" Console.WriteLine(full) ' Anna Silva
The & operator is the recommended one for concatenating, since it automatically converts numbers to text. The + can cause ambiguity with addition.
Comments
' This is a line comment
Dim x = 10 ' comment at the end of the line
REM Also works (old, rarely used)
''' <summary>
''' XML documentation comment
''' </summary>
''' <param name="n">The number</param>
Function Double(n As Integer) As Integer
Return n * 2
End FunctionThe despuéstrophe &after; starts a comment. XML comments with &after;&after;&after; generate IntelliSense documentation for the methods.
Data Types
' Integers: Byte, Short, Integer, Long ' Decimals: Single, Double, Decimal ' Others: 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 = "anything" ' Literal suffixes: Dim l = 100L ' Long Dim f = 1.5F ' Single Dim dec = 9.9D ' Decimal
VB.NET uses the .NET types. Date literals go between #, and suffixes like L, F and D indicate the numeric type.
Ternary Operator If()
Dim age = 20 ' If(condition, valueIfTrue, valueIfFalse) Dim status = If(age >= 18, "Adult", "Minor") Console.WriteLine(status) ' Adult ' Coalescing (first non-Nothing): Dim name As String = Nothing Dim display = If(name, "Anonymous") Console.WriteLine(display) ' Anonymous
The If() function with 3 arguments acts the a ternary. With 2 arguments, it works the coalescing: it returns the first value that is not Nothing.
Line Continuation
' Modern VB.NET: automatic break in most cases
Dim result = 1 + 2 +
3 + 4
Dim list = New List(Of String) From {
"Anna",
"Ray",
"Mia"
}
' Old (VB9 and earlier): use _ (underscore)
Dim total = 1 + _
2 + 3In modern versions the line break is automatic on operators and lists. In old code the continuation character _ (underscore) was used at the end of the line.
Arithmetic Operators
Dim a = 10, b = 3 Dim total = a + b ' 13 Dim diff = a - b ' 7 Dim prod = a * b ' 30 Dim realDiv = a / b ' 3.333... (Double) Dim intDiv = a \ b ' 3 (integer division) Dim remainder = a Mod b ' 1 Dim power = 2 ^ 10 ' 1024 a += 1 ' a = a + 1 a -= 1 ' a = a - 1
The slash / does real division and the backslash \ does integer division. Mod gives the remainder and ^ the power.
Type Conversions
' Conversion functions:
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
' Safe conversion (does not throw):
Dim result As Integer
Dim ok = Integer.TryParse("42", result) ' True
' ToString:
Dim txt = 42.ToString() ' "42"
Dim fmt = 3.14159.ToString("F2") ' "3.14"The CInt, CDbl and CStr functions convert types. To avoid exceptions on invalid text, use TryParse, which returns True or False.
Multiple Declarations
' Several variables on the same line: Dim x = 1, y = 2, z = 3 ' Same explicit type: Dim a, b, c As Integer ' only c is Integer! ' a and b become Object (careful) ' Safe form: Dim i As Integer = 0 Dim j As Integer = 0 ' Compound assignment: x += 5 ' x = x + 5 y *= 2 ' y = y * 2
Warning: in Dim a, b, c As Integer only c becomes Integer; the others become Object. Prefer declaring each variable with its own type.
Functions and Procedures
Function (with Return)
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
' Call:
Dim r = Add(3, 4) ' 7
' Single-expression Function:
Function Double(n As Integer) As Integer
Return n * 2
End FunctionA Function returns a value with Return and declares the return type with As. The function name describes what it does.
ByVal and ByRef
' ByVal (copy - the default):
Sub Increment(ByVal n As Integer)
n += 1 ' does not affect the original
End Sub
' ByRef (reference - changes the original):
Sub Swap(ByRef a As Integer, ByRef b As Integer)
Dim temp = a
a = b
b = temp
End Sub
Dim x = 1, y = 2
Swap(x, y) ' x = 2, y = 1ByVal passes a copy (the original does not change); ByRef passes the reference (the original is changed). In VB.NET the default is ByVal.
Extension Methods
Imports System.Runtime.CompilerServices
<Extension()>
Function Repeat(s As String, n As Integer) As String
Return String.Concat(Enumerable.Repeat(s, n))
End Function
' Used the if it were a String method:
Dim r = "ab".Repeat(3) ' "ababab"Extension methods add methods to existing types without modifying them. They need the <Extension()> attribute and a Module; the 1st parameter is the extended type.
Sub (No Return)
Sub Print(msg As String)
Console.WriteLine(msg)
End Sub
' Call:
Print("Hello!")
' Sub can end early with Exit Sub:
Sub Validate(n As Integer)
If n < 0 Then Exit Sub
Console.WriteLine(n)
End SubA Sub runs actions without returning a value. Use Exit Sub to end before the end. It is ideal for printing or validation procedures.
Lambda Functions
' Single-expression lambda:
Dim double = Function(x As Integer) x * 2
Dim add = Function(a As Integer, b As Integer) a + b
Console.WriteLine(double(5)) ' 10
Console.WriteLine(add(3, 4)) ' 7
' Lambda Sub (no return):
Dim print = Sub(msg As String) Console.WriteLine(msg)
print("Hello")A lambda is a short anonymous function. Function(...) returns a value; Sub(...) performs an action. They are widely used with LINQ and events.
Properties
Private _name As String
Public Property Name As String
Get
Return _name
End Get
Set(value As String)
_name = value.Trim()
End Set
End Property
' Auto-property (no manual field):
Public Property Age As Integer
' Read-only:
Public ReadOnly Property UpperName As String
Get
Return _name.ToUpper()
End Get
End PropertyA Property exposes a field with Get and Set. Auto-properties skip the private field. ReadOnly creates read-only properties.
Optional and Named Parameters
Function Greet(name As String,
Optional prefix As String = "Hello") As String
Return $"{prefix}, {name}!"
End Function
' Use the default value:
Console.WriteLine(Greet("Anna")) ' Hello, Anna!
' Named argument:
Console.WriteLine(Greet("Ray", prefix:="Good morning"))Parameters with Optional need a default value. Named arguments (prefix:=) let you skip optional parameters clearly.
Multi-line Lambda
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 classify = Function(n As Integer)
If n > 0 Then Return "positive"
If n < 0 Then Return "negative"
Return "zero"
End FunctionMulti-line lambdas end with End Function (or End Sub). The body can have If, loops and multiple Return.
Iterators (Yield)
Function Count(max As Integer) As IEnumerable(Of Integer)
For i = 1 To max
Yield i
Next
End Function
' Lazy consumption:
For Each n In Count(5)
Console.WriteLine(n) ' 1 2 3 4 5
NextThe Yield returns one element at a time, creating a lazy sequence. The function returns IEnumerable(Of T) and only generates values when iterated.
ParamArray (Variable Number of Arguments)
Function AddAll(ParamArray nums() As Integer) As Integer
Dim total = 0
For Each n In nums
total += n
Next
Return total
End Function
' Call with several arguments:
Console.WriteLine(AddAll(1, 2, 3)) ' 6
Console.WriteLine(AddAll(10, 20, 30, 40)) ' 100ParamArray accepts a variable number of arguments, treated the an array inside the function. It must be the last parameter in the list.
Local Functions
Function Calculate(n As Integer) As Integer
' Local function, only visible in here:
Function Square(x As Integer) As Integer
Return x * x
End Function
Return Square(n) + Square(n + 1)
End Function
Console.WriteLine(Calculate(3)) ' 9 + 16 = 25Local functions are declared inside another Function and only exist in that scope. They help organize helper logic without polluting the class.
Recursive Functions
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 55A recursive function calls itself. It always needs a base case (If n <= 1 Then Return n) to stop, otherwise it enters an infinite loop.
Strings and Formatting
String Methods
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()) ' removes spaces
Console.WriteLine(s.IndexOf("World")) ' 6Strings have methods like ToUpper, Substring, Contains and Replace. Strings are immutable: each method returns a new string.
Verbatim and Escaping
' Double quotes are escaped by doubling: Dim s = "He said ""Hello""" ' File paths (no \ escaping): Dim path = "C:\Users\Anna\docs" ' New line and tab: Dim text = "Line1" & vbCrLf & "Line2" & vbTab & "end" ' Useful constants: Console.WriteLine(vbCrLf) ' new line (Windows) Console.WriteLine(vbTab) ' tab Console.WriteLine(vbNullString) ' empty string
In VB.NET quotes are escaped by doubling (""), not with a backslash. vbCrLf and vbTab are constants for new line and tab.
Working with Dates
Dim today = Date.Now
Dim d = #2024-01-15#
Console.WriteLine(today.Year)
Console.WriteLine(today.Month)
Console.WriteLine(today.Day)
Console.WriteLine(today.DayOfWeek)
' Format:
Console.WriteLine(today.ToString("dd/MM/yyyy"))
Console.WriteLine(today.ToString("yyyy-MM-dd HH:mm"))
' Date arithmetic:
Dim tomorrow = today.AddDays(1)
Dim diff = (tomorrow - today).TotalDays ' 1The Date (or DateTime) type has Year, Month, Day properties. Methods like AddDays add time and subtraction gives a TimeSpan.
Split and Join
Dim csv = "Anna,Ray,Mia"
' Split by character:
Dim parts = csv.Split(","c)
For Each p In parts
Console.WriteLine(p)
Next
' Split by several separators:
Dim phrase = "one two;three"
Dim words = phrase.Split({" "c, ";"c}, StringSplitOptions.RemoveEmptyEntries)
' Join:
Dim joined = String.Join(" | ", parts) ' "Anna | Ray | Mia"Split divides a string into an array by a separator (the c suffix indicates a Char). String.Join joins elements with a delimiter.
StringBuilder
Imports System.Text
Dim sb As New StringBuilder()
For i = 1 To 5
sb.Append("Line ").AppendLine(i.ToString())
Next
sb.Insert(0, "=== Start ===" & vbCrLf)
sb.Replace("Line", "Item")
Dim result = sb.ToString()
Console.WriteLine(result)The StringBuilder is efficient for building strings in loops, since it does not create a new object on every change. Use Append, AppendLine and ToString.
Text Conversions
Dim s = "123"
' Text to number:
Dim n = Integer.Parse(s)
Dim d = Double.Parse("3.14")
' Number to text:
Dim txt = n.ToString()
Dim hex = 255.ToString("X") ' "FF"
Dim bin = Convert.ToString(5, 2) ' "101"
' Character to code:
Dim code = Asc("A") ' 65
Dim letter = Chr(65) ' "A"Parse converts text into a number (throws an exception if invalid). Asc gives the code of a character and Chr does the reverse.
String Interpolation
Dim name = "Anna"
Dim age = 30
' Interpolation with $:
Console.WriteLine($"{name} is {age} years old")
Console.WriteLine($"In 5 years: {age + 5}")
' With alignment and format:
Console.WriteLine($"|{name,-10}|{age,5}|")
' Multi-line string:
Dim text = $"Hello {name},
welcome!"Interpolation with $ inserts expressions inside {}. You can align with a comma ({name,-10}) and format with a colon.
String Comparison
Dim a = "Hello"
Dim b = "hello"
' Case-sensitive:
Console.WriteLine(a = b) ' False
' Ignoring case:
Console.WriteLine(String.Equals(a, b, StringComparison.OrdinalIgnoreCase)) ' True
Console.WriteLine(a.Equals(b, StringComparison.CurrentCultureIgnoreCase))
' Compare order:
Console.WriteLine(String.Compare("abc", "abd")) ' negativeBy default the comparison is case-sensitive. Use StringComparison.OrdinalIgnoreCase to ignore capitalization in Equals and Compare.
Checking String Content
Dim s = "Hello World"
Console.WriteLine(s.StartsWith("Hello")) ' True
Console.WriteLine(s.EndsWith("World")) ' True
Console.WriteLine(s.Contains("Wor")) ' True
' Empty or null:
Dim x As String = ""
Console.WriteLine(String.IsNullOrEmpty(x)) ' True
Console.WriteLine(String.IsNullOrWhiteSpace(" ")) ' True
' Reverse:
Dim rev = StrReverse("abc") ' "cba"StartsWith, EndsWith and Contains check content. IsNullOrWhiteSpace is the safest check for user input.
String.Format
Dim name = "Anna"
Dim age = 30
' Format with positions:
Dim msg = String.Format("{0} is {1} years old", name, age)
' Reuse the same position:
Dim r = String.Format("{0} + {0} = {1}", 5, 10) ' "5 + 5 = 10"
' Numeric formatting:
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 replaces the {0}, {1} placeholders with the arguments. The F2, D5 and X codes format numbers.
Pad, Trim and Remove
Dim s = " Hello "
Console.WriteLine(s.Trim()) ' "Hello"
Console.WriteLine(s.TrimStart()) ' "Hello "
Console.WriteLine(s.TrimEnd()) ' " Hello"
' Pad to a size:
Console.WriteLine("42".PadLeft(5, "0"c)) ' "00042"
Console.WriteLine("Hi".PadRight(6, "."c)) ' "Hi...."
' Remove a part:
Console.WriteLine("Hello World".Remove(5)) ' "Hello"
Console.WriteLine("Hello World".Remove(5, 3)) ' "Hellorld"Trim removes spaces at the ends. PadLeft/PadRight pad up to a size. Remove deletes from an index.
Regular Expressions
Imports System.Text.RegularExpressions
Dim text = "Contact: 912345678 or 923456789"
' Find all matches:
Dim matches = Regex.Matches(text, "\d{9}")
For Each m As Match In matches
Console.WriteLine(m.Value)
Next
' Replace:
Dim clean = Regex.Replace(text, "\d", "*")
' Validate:
Dim ok = Regex.IsMatch("ana@mail.com",
"^[\w.]+@[\w.]+\.\w+$")The Regex class does advanced pattern searching. Matches finds all occurrences, Replace substitutes and IsMatch validates.
Classes e OOP
Class and Constructor
Public Class Person
Public Property Name As String
Public Property Age As Integer
' Constructor:
Public Sub New(name As String, age As Integer)
Me.Name = name
Me.Age = age
End Sub
Public Function Greeting() As String
Return $"Hello, I am {Name}"
End Function
End Class
Dim p As New Person("Anna", 30)A class is defined with Class...End Class. The constructor is the Sub New method and Me refers to the current instance.
NotInheritable and Shadows
' Sealed class (cannot be inherited):
Public NotInheritable Class Utility
Public Shared Function Version() As String
Return "1.0"
End Function
End Class
' Shadows: hides the base member:
Public Class Base
Public Function Info() As String
Return "Base"
End Function
End Class
Public Class Child
Inherits Base
Public Shadows Function Info() As String
Return "Child"
End Function
End ClassNotInheritable prevents inheritance (sealed class). Shadows hides an inherited member with a new one of the same name, without polymorphism.
Enum
Public Enum WeekDay
Monday = 1
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday
End Enum
Dim day = WeekDay.Friday
Console.WriteLine(day) ' Friday
Console.WriteLine(CInt(day)) ' 5
' Convert from a number:
Dim d = CType(3, WeekDay) ' WednesdayAn Enum defines a set of named constants. Values are integers by default (starting at 0 or at the given value). CType converts numbers into enum.
Access Modifiers
Public Class Account
Public Balance As Decimal ' accessible everywhere
Private _code As String ' only inside the class
Protected Holder As String ' class and derived
Friend Bank As String ' only in the same assembly
Public Sub New()
_code = GenerateCode() ' accesses the private member
End Sub
Private Function GenerateCode() As String
Return Guid.NewGuid().ToString()
End Function
End ClassPublic is accessible everywhere; Private only in the class; Protected in the class and derived ones; Friend only within the same assembly.
Interfaces
Public Interface ISwimmer
Sub Swim()
End Interface
Public Interface IRunner
Sub Run()
End Interface
Public Class Athlete
Implements ISwimmer, IRunner
Public Sub Swim() Implements ISwimmer.Swim
Console.WriteLine("Swimming")
End Sub
Public Sub Run() Implements IRunner.Run
Console.WriteLine("Running")
End Sub
End ClassAn Interface defines a contract without implementation. The class uses Implements to adopt it and links each method with Implements Name.Member.
Structure (Value Type)
Public Structure Point
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 Distance() As Double
Return Math.Sqrt(X ^ 2 + Y ^ 2)
End Function
End Structure
Dim p As New Point(3, 4)
Console.WriteLine(p.Distance()) ' 5A Structure is a value type (stored on the stack), ideal for small data. Unlike classes, it does not support inheritance and copying is done by value.
Inheritance
Public Class Animal
Public Property Name As String
Public Overridable Function Sound() As String
Return "..."
End Function
End Class
Public Class Dog
Inherits Animal
Public Overrides Function Sound() As String
Return "Woof woof!"
End Function
End Class
Dim d As New Dog()
Console.WriteLine(d.Sound()) ' Woof woof!Inherits creates a derived class. Overridable allows redefining a method in the base; Overrides provides the new implementation in the derived class.
Shared (Static)
Public Class Counter
Public Shared Total As Integer = 0
Public Sub New()
Total += 1
End Sub
Public Shared Function GetTotal() As Integer
Return Total
End Function
End Class
Dim a As New Counter()
Dim b As New Counter()
Console.WriteLine(Counter.Total) ' 2Shared members belong to the class and not to the instance. They are accessed through the class name (Counter.Total) and are shared by all objects.
Generics
' Generic class:
Public Class Box(Of T)
Public Property Value As T
Public Sub New(value As T)
Me.Value = value
End Sub
End Class
Dim b1 As New Box(Of Integer)(42)
Dim b2 As New Box(Of String)("hello")
Console.WriteLine(b1.Value) ' 42
Console.WriteLine(b2.Value) ' helloGenerics use (Of T) to create reusable types with any data type. The same code works for Integer, String, etc.
MustInherit and MustOverride
' Abstract class (cannot be instantiated):
Public MustInherit Class Shape
Public MustOverride Function Area() As Double
Public Function Describe() As String
Return $"Area: {Area()}"
End Function
End Class
Public Class Circle
Inherits Shape
Public Radius As Double
Public Overrides Function Area() As Double
Return Math.PI * Radius ^ 2
End Function
End ClassMustInherit makes the class abstract (not instantiable). MustOverride declares a method without a body that derived classes are required to implement.
Overrides and Overloads
Public Class Calculator
' Overloads: same name, different parameters
Public Overloads Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
Public Overloads Function Add(a As Double, b As Double) As Double
Return a + b
End Function
Public Overloads Function Add(nums() As Integer) As Integer
Return nums.Sum()
End Function
End ClassOverloads allows several methods with the same name but different signatures (number or type of parameters). The compiler picks the right one based on the call.
Generic Constraints
' T must be a class (reference type):
Public Class Repo(Of T As Class)
End Class
' T must implement an interface:
Public Class Sorter(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 must have a parameterless constructor:
Public Class Factory(Of T As New)
Public Function Create() As T
Return New T()
End Function
End ClassConstraints (As Class, As New, As IComparable) limit the types accepted by a generic, allowing specific methods to be used safely.
Advanced
Async / Await
Async Function DownloadAsync(url As String) As Task(Of String)
Using client As New HttpClient()
Dim result = Await client.GetStringAsync(url)
Return result
End Using
End Function
' Call:
Async Function RunAsync() As Task
Dim data = Await DownloadAsync("https://api.example.com")
Console.WriteLine(data)
End FunctionAsync methods return Task or Task(Of T). The Await pauses without blocking the thread, freeing the interface for other tasks.
Events
Public Class Thermometer
Public Event OnChange(sender As Object, temp As Double)
Private _temp As Double
Public Property Temperature As Double
Get
Return _temp
End Get
Set(value As Double)
_temp = value
RaiseEvent OnChange(Me, value)
End Set
End Property
End ClassAn Event notifies subscribers when something happens. RaiseEvent fires the event. It is the pattern used in graphical interfaces and observers.
Reflection
Imports System.Reflection
Dim type = GetType(Person)
Console.WriteLine(type.Name) ' "Person"
Console.WriteLine(type.FullName)
' List methods:
For Each m As MethodInfo In type.GetMethods()
Console.WriteLine(m.Name)
Next
' List properties:
For Each p In type.GetProperties()
Console.WriteLine($"{p.Name}: {p.PropertyType.Name}")
NextReflection (GetType, GetMethods, GetProperties) inspects types at runtime. It is used by serializers and frameworks.
Task and Task.Run
' Run work in the background:
Async Function ProcessAsync() As Task(Of Integer)
Dim result = Await Task.Run(Function()
Threading.Thread.Sleep(1000)
Return 42
End Function)
Return result
End Function
' Several tasks in parallel:
Dim t1 = DownloadAsync("url1")
Dim t2 = DownloadAsync("url2")
Await Task.WhenAll(t1, t2)Task.Run executes code on a pool thread. Task.WhenAll awaits several tasks in parallel, improving performance for independent operations.
AddHandler and Handles
Dim t As New Thermometer()
' Subscribe at runtime:
AddHandler t.OnChange,
Sub(sender, temp) Console.WriteLine($"Temp: {temp}")
t.Temperature = 36.5 ' prints "Temp: 36.5"
' Or with Handles (in a class):
Private Sub OnChangeHandler(sender As Object, temp As Double) _
Handles t.OnChange
Console.WriteLine($"Changed to {temp}")
End Sub
' Remove:
RemoveHandler t.OnChange, AddressOf OnChangeHandlerAddHandler subscribes to an event at runtime; Handles binds it at compile time. RemoveHandler cancels the subscription.
Attributes
<Obsolete("Use NewMethod instead of this one")>
Public Sub OldMethod()
End Sub
' Attribute with parameters:
<DebuggerDisplay("Name={Name}, Age={Age}")>
Public Class Person
Public Property Name As String
Public Property Age As Integer
End Class
' Assembly attribute:
<Assembly: AssemblyVersion("1.0.0.0")>Attributes (between < >) add metadata to the code. Obsolete marks deprecated code; DebuggerDisplay customizes debugging.
Delegates
' Declare a delegate:
Public Delegate Function Operation(a As Integer, b As Integer) As Integer
Function Add(a As Integer, b As Integer) As Integer
Return a + b
End Function
' Use:
Dim op As Operation = AddressOf Add
Dim r = op(3, 4) ' 7
' Point to a lambda:
Dim op2 As Operation = Function(a, b) a * b
Console.WriteLine(op2(3, 4)) ' 12A Delegate is a type that references a method. AddressOf binds it to an existing method. It is the basis of events and callbacks in VB.NET.
Nullable Types
' Value type that can be 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 ' Coalescing operator: Dim y As Integer? = Nothing Dim result = If(y, 0) ' 0 if y is Nothing
A Nullable type (Integer?) can hold Nothing besides the normal value. HasValue and Value check and get the value safely.
Nothing and Is Operators
Dim s As String = Nothing
' Compare with Nothing:
If s Is Nothing Then
Console.WriteLine("no value")
End If
If s IsNot Nothing Then
Console.WriteLine(s.Length)
End If
' Same reference:
Dim a As New Object()
Dim b = a
Console.WriteLine(a Is b) ' True (same object)
Console.WriteLine(a IsNot b) ' FalseUse Is Nothing and IsNot Nothing to check null references. Is compares object identity, not value equality.
Action and Func
' Func: returns a value (last type is the return):
Dim double As Func(Of Integer, Integer) = Function(x) x * 2
Console.WriteLine(double(5)) ' 10
Dim add As Func(Of Integer, Integer, Integer) =
Function(a, b) a + b
' Action: does not return a value:
Dim print As Action(Of String) = Sub(msg) Console.WriteLine(msg)
print("Hello")
' Predicate: returns Boolean:
Dim even As Predicate(Of Integer) = Function(n) n Mod 2 = 0
Console.WriteLine(even(4)) ' TrueFunc and Action are ready-made delegates: Func returns a value, Action does not. They avoid declaring custom delegates for simple cases.
TypeOf and CType
Dim obj As Object = "Hello"
' Check the type:
If TypeOf obj Is String Then
Console.WriteLine("It is a string")
End If
' Convert (throws an exception if it fails):
Dim s = CType(obj, String)
' Safe conversion (returns Nothing if it fails):
Dim n = TryCast(obj, Integer) ' Nothing
If n IsNot Nothing Then
Console.WriteLine(n)
End IfTypeOf...Is checks the type at runtime. CType converts (throws an exception if impossible); TryCast returns Nothing instead of failing.
NameOf and Interpolation
Public Sub Validate(name As String)
If String.IsNullOrEmpty(name) Then
' NameOf returns the parameter name:
Throw New ArgumentException("Invalid", NameOf(name))
End If
End Sub
Console.WriteLine(NameOf(Validate)) ' "Validate"
Console.WriteLine(NameOf(Person.Name)) ' "Name"NameOf returns the name of a symbol the a string, at compile time. It is useful in error messages and notifications, avoiding hand-written strings.
Flow Control
If / ElseIf / Else
Dim age = 20
If age >= 18 Then
Console.WriteLine("Adult")
ElseIf age >= 12 Then
Console.WriteLine("Teenager")
Else
Console.WriteLine("Child")
End If
' Single-line (without End If):
If age > 0 Then Console.WriteLine("positive")The If...Then...End If block always ends with End If. In single-line statements the End If is optional.
While and Do Loop
Dim x = 5
' While (checks before):
While x > 0
x -= 1
End While
' Do Until (repeats until true):
x = 0
Do Until x = 10
x += 1
Loop
' Do While (repeats while true):
Do While x > 0
x -= 1
LoopWhile...End While repeats while the condition is true. Do Until repeats until the condition becomes true; Do While repeats while it is true.
Throw and Custom Exceptions
Sub SetAge(age As Integer)
If age < 0 Then
Throw New ArgumentException("Invalid age")
End If
End Sub
' Custom exception:
Public Class InsufficientBalanceException
Inherits Exception
Public Sub New(msg As String)
MyBase.New(msg)
End Sub
End Class
Throw New InsufficientBalanceException("No funds")Throw raises an exception. You can create your own exceptions by inheriting from Exception and calling MyBase.New to pass the message.
Select Case
Dim day = 3
Select Case day
Case 1
Console.WriteLine("Monday")
Case 2, 3
Console.WriteLine("Tuesday or Wednesday")
Case 4 To 6
Console.WriteLine("Midweek")
Case Is >= 7
Console.WriteLine("Weekend")
Case Else
Console.WriteLine("Invalid")
End SelectThe Select Case is the VB switch. It supports single values, lists (Case 2, 3), ranges (Case 4 To 6) and conditions with Is.
Do with Condition at the End
Dim n = 0
' The condition is tested AFTER (runs at least once):
Do
n += 1
Console.WriteLine(n)
Loop Until n >= 5
Do
n -= 1
Loop While n > 0When the condition comes after the Loop, the block always runs at least once. It is useful for menus and input validation.
When (Exception Filter)
Try
Dim n = CInt(Console.ReadLine())
Catch ex As FormatException When ex.Message.Contains("input")
Console.WriteLine("Specific format")
Catch ex As Exception When TypeOf ex Is OverflowException
Console.WriteLine("Value too large")
Catch ex As Exception
Console.WriteLine("Other error")
End TryThe When clause filters exceptions by a boolean condition. Only the Catch whose filter returns True is executed.
For ... Next
' Ascending count:
For i As Integer = 1 To 10
Console.WriteLine(i)
Next
' Descending count with Step:
For i = 10 To 1 Step -1
Console.WriteLine(i)
Next
' Step of 2:
For i = 0 To 20 Step 2
Console.WriteLine(i)
NextThe For...Next loop repeats a block a defined number of times. The Step defines the increment (it can be negative to count backwards).
Exit and Continue
For i = 1 To 10
If i = 3 Then Continue For ' skips to the next
If i = 8 Then Exit For ' exits the loop
Console.WriteLine(i)
Next
' Prints: 1 2 4 5 6 7
While True
Dim cmd = Console.ReadLine()
If cmd = "quit" Then Exit While
End WhileContinue For jumps to the next iteration; Exit For ends the loop immediately. There are also Exit While, Exit Do and Exit Sub.
Using (Automatic Resources)
Imports System.IO
Using reader As New StreamReader("data.txt")
Dim line = reader.ReadLine()
Console.WriteLine(line)
End Using
' reader is closed/disposed automatically here
' Several resources:
Using fs = File.OpenRead("a.txt"),
sr = New StreamReader(fs)
Console.WriteLine(sr.ReadToEnd())
End UsingThe Using block guarantees that objects holding resources (files, connections) are released automatically at the end, even if an exception occurs.
For Each
Dim fruits = {"Apple", "Pear", "Grape"}
For Each fruit In fruits
Console.WriteLine(fruit)
Next
' With index (if you need the position):
For i = 0 To fruits.Length - 1
Console.WriteLine($"{i}: {fruits(i)}")
NextThe For Each iterates over each element of a collection without needing an index. Use the regular For when you need the element position.
Try / Catch / Finally
Try
Dim r = 10 \ 0
Catch ex As DivideByZeroException
Console.WriteLine("Division by zero!")
Catch ex As Exception
Console.WriteLine($"Error: {ex.Message}")
Finally
Console.WriteLine("Always runs")
End TryThe Try block protects code that may fail. The Catch captures the exception (there can be several, from most specific to general) and the Finally always runs.
With (Member Access)
Dim p As New Person()
With p
.Name = "Anna"
.Age = 30
.Email = "ana@mail.com"
End With
' Equivalent to:
' p.Name = "Anna"
' p.Age = 30
' p.Email = "ana@mail.com"
Console.WriteLine(p.Name)The With block avoids repeating the object name when setting several properties. The dot . refers to the With object.
Collections and LINQ
Arrays
' Declare and initialize:
Dim nums() As Integer = {1, 2, 3, 4, 5}
Dim names = {"Anna", "Ray", "Mia"}
' Access (index starts at 0):
Console.WriteLine(nums(0)) ' 1
nums(0) = 10
' Size:
Console.WriteLine(nums.Length) ' 5An array has fixed size and index starting at 0. Length returns the number of elements. Values are defined between braces {}.
List(Of T)
Dim list As New List(Of String)
list.Add("Anna")
list.Add("Ray")
list.Insert(0, "Mia") ' inserts at the start
list.Remove("Anna") ' removes by value
list.RemoveAt(0) ' removes by index
Console.WriteLine(list.Count) ' 1
Console.WriteLine(list.Contains("Ray")) ' True
Console.WriteLine(list(0)) ' RayThe List(Of T) is a dynamic array that grows automatically. It has Add, Insert, Remove and the Count property.
HashSet(Of T)
Dim set As New HashSet(Of Integer) From {1, 2, 3}
set.Add(3) ' ignored (already exists)
set.Add(4)
Console.WriteLine(set.Count) ' 4
Console.WriteLine(set.Contains(2)) ' True
' Set operations:
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}The HashSet stores unique values without duplicates and with fast existence checks. It has operations like IntersectWith, UnionWith and ExceptWith.
ReDim and Preserve
Dim nums(4) As Integer ' 5 elements (0 to 4) ' Resize (loses the data): ReDim nums(9) ' Resize keeping the data: Dim list(2) As String list(0) = "A" list(1) = "B" ReDim Preserve list(5) ' keeps A and B Console.WriteLine(list.Length) ' 6
ReDim changes the array size. Without Preserve the data is lost; with Preserve the existing elements are kept.
List - Search and Sort
Dim nums As New List(Of Integer) From {5, 2, 8, 1, 9}
nums.Sort() ' sorts
nums.Reverse() ' reverses
' Find with a predicate:
Dim over5 = nums.Find(Function(n) n > 5)
Dim allEven = nums.FindAll(Function(n) n Mod 2 = 0)
' Remove with a condition:
nums.RemoveAll(Function(n) n < 3)
Dim found = nums.Exists(Function(n) n = 8)Find returns the first element that satisfies the predicate; FindAll returns them all. RemoveAll and Exists also take a lambda.
LINQ - Query Syntax
Dim nums = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim evens = From n In nums
Where n Mod 2 = 0
Order By n Descending
Select n * 2
For Each r In evens
Console.WriteLine(r)
NextThe LINQ query syntax looks like SQL: From defines the source, Where filters, Order By sorts and Select projects the result.
Array Operations
Dim nums = {5, 2, 8, 1, 9}
Array.Sort(nums) ' sorts: 1 2 5 8 9
Array.Reverse(nums) ' reverses: 9 8 5 2 1
Dim pos = Array.IndexOf(nums, 5) ' position of 5
Dim found = nums.Contains(8) ' True
Dim total = nums.Sum()
Dim biggest = nums.Max()
Dim mean = nums.Average()The Array class offers Sort, Reverse and IndexOf. LINQ extension methods like Sum, Max and Average do quick calculations.
Dictionary(Of TKey, TValue)
Dim ages As New Dictionary(Of String, Integer)
ages("Anna") = 30
ages.Add("Ray", 25)
ages("Mia") = 22
Console.WriteLine(ages("Anna")) ' 30
Console.WriteLine(ages.ContainsKey("Ray")) ' True
Console.WriteLine(ages.Count) ' 3
' Safe access:
Dim value As Integer
If ages.TryGetValue("Joe", value) Then
Console.WriteLine(value)
End IfThe Dictionary stores key/value pairs with fast access by key. TryGetValue avoids an exception when the key does not exist.
LINQ - Method Syntax
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()
' Other useful methods:
Dim total = nums.Sum()
Dim evens = nums.Count(Function(n) n Mod 2 = 0)
Dim first = nums.First(Function(n) n > 3)The method syntax chains operators like Where, OrderBy and Take using lambdas. Sum, Count and First do aggregations.
Multidimensional Arrays
' 2D matrix (3 rows x 3 columns):
Dim matrix(,) As Integer = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
}
Console.WriteLine(matrix(1, 2)) ' 6
' Iterate:
For i = 0 To matrix.GetLength(0) - 1
For j = 0 To matrix.GetLength(1) - 1
Console.Write(matrix(i, j) & " ")
Next
Console.WriteLine()
NextMultidimensional arrays use a comma in the declaration: (,) for 2D. GetLength(0) gives the number of rows and GetLength(1) the number of columns.
Iterating a Dictionary
Dim ages As New Dictionary(Of String, Integer) From {
{"Anna", 30},
{"Ray", 25},
{"Mia", 22}
}
For Each pair In ages
Console.WriteLine($"{pair.Key}: {pair.Value}")
Next
' Only the keys / only the values:
For Each name In ages.Keys
Console.WriteLine(name)
NextWhen iterating a Dictionary each element is a pair with Key and Value. The Keys and Values properties give separate access.
LINQ - Projection and Grouping
Dim people = GetPeople()
' Projection (Select):
Dim names = people.Select(Function(p) p.Name).ToList()
' Grouping:
Dim byCity = From p In people
Group By p.City Into Grp = Group
Select City, Total = Grp.Count()
' Distinct:
Dim cities = people.Select(Function(p) p.City).Distinct()Select transforms each element. Group By...Into Group groups by a key and Distinct removes duplicates from the result.
Input/Output and Files
Console Input and Output
' Output:
Console.WriteLine("With new line")
Console.Write("Without new line")
Console.WriteLine($"Value: {42}")
' Input:
Console.Write("Name: ")
Dim name = Console.ReadLine()
' Read a number:
Console.Write("Age: ")
Dim age = CInt(Console.ReadLine())
' Clear and colors:
Console.ForegroundColor = ConsoleColor.Green
Console.WriteLine("Success!")
Console.ResetColor()Console.WriteLine writes with a new line; ReadLine reads a line the a string. ForegroundColor changes the text color in the console.
Paths (Path)
Imports System.IO
Dim path = "C:\data\report.txt"
Console.WriteLine(Path.GetFileName(path)) ' "report.txt"
Console.WriteLine(Path.GetExtension(path)) ' ".txt"
Console.WriteLine(Path.GetFileNameWithoutExtension(path))
Console.WriteLine(Path.GetDirectoryName(path))
' Join paths safely:
Dim joined = Path.Combine("C:\data", "sub", "f.txt")
' Temporary file:
Dim temp = Path.GetTempFileName()The Path class manipulates paths without separator errors. Path.Combine joins parts safely and GetExtension gets the extension.
Accessing a Database
Imports System.Data.SqlClient
Dim connStr = "Server=.;Database=Shop;Trusted_Connection=True;"
Using conn As New SqlConnection(connStr)
conn.Open()
Using cmd As New SqlCommand("SELECT Name FROM Customer", conn)
Using reader = cmd.ExecuteReader()
While reader.Read()
Console.WriteLine(reader("Name"))
End While
End Using
End Using
End UsingADO.NET access: SqlConnection connects to the database, SqlCommand runs the query and ExecuteReader iterates the results. Always use Using.
Writing Files
Imports System.IO
' Write everything at once:
File.WriteAllText("f.txt", "Hello World")
' Several lines:
File.WriteAllLines("f.txt", {"L1", "L2", "L3"})
' Append to the end:
File.AppendAllText("log.txt", "new line" & vbCrLf)
' With StreamWriter (more control):
Using sw As New StreamWriter("f.txt")
sw.WriteLine("Line 1")
sw.WriteLine("Line 2")
End UsingFile.WriteAllText and WriteAllLines create/overwrite files. AppendAllText appends. The StreamWriter gives more control for progressive writing.
Listing Files and Folders
Imports System.IO
' List files:
For Each f In Directory.GetFiles("C:\data")
Console.WriteLine(f)
Next
' With filter and recursion:
Dim txts = Directory.GetFiles("C:\data", "*.txt",
SearchOption.AllDirectories)
' List folders:
For Each d In Directory.GetDirectories("C:\data")
Console.WriteLine(d)
Next
' Lazy version (memory efficient):
For Each f In Directory.EnumerateFiles("C:\data", "*.log")
Console.WriteLine(f)
NextGetFiles and GetDirectories list contents. The *.txt filter selects by extension and SearchOption.AllDirectories searches recursively.
SQL Parameters (Anti-Injection)
Using conn As New SqlConnection(connStr)
conn.Open()
Dim sql = "SELECT * FROM Customer WHERE Age > @age"
Using cmd As New SqlCommand(sql, conn)
cmd.Parameters.AddWithValue("@age", 18)
Dim count = CInt(cmd.ExecuteScalar())
Console.WriteLine($"Adults: {count}")
End Using
End Using
' Insert with parameters:
Dim ins = "INSERT INTO Customer (Name) VALUES (@name)"Always use parameters (@age) instead of concatenating strings into queries. This prevents SQL injection. ExecuteScalar returns a single value.
Reading Files
Imports System.IO
' Read everything the text:
Dim content = File.ReadAllText("f.txt")
' Read the an array of lines:
Dim lines = File.ReadAllLines("f.txt")
For Each line In lines
Console.WriteLine(line)
Next
' With StreamReader (line by line):
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 returns the whole file; ReadAllLines returns an array of lines. The StreamReader is efficient for large files, reading line by line.
JSON Serialization
Imports System.Text.Json
Public Class Person
Public Property Name As String
Public Property Age As Integer
End Class
' Serialize:
Dim p As New Person With {.Name = "Anna", .Age = 30}
Dim json = JsonSerializer.Serialize(p)
' Deserialize:
Dim p2 = JsonSerializer.Deserialize(Of Person)(json)
Console.WriteLine(p2.Name) ' AnnaJsonSerializer.Serialize converts an object into JSON; Deserialize(Of T) does the opposite. It is included in System.Text.Json in modern .NET.
Checking and Managing Files
Imports System.IO
' Check existence:
If File.Exists("f.txt") Then
Console.WriteLine("Exists")
End If
If Directory.Exists("folder") Then
Console.WriteLine("Folder exists")
End If
' Create folder:
Directory.CreateDirectory("data/logs")
' Delete:
File.Delete("temp.txt")
' Move / copy:
File.Copy("a.txt", "b.txt", overwrite:=True)
File.Move("a.txt", "c.txt")File.Exists and Directory.Exists check existence. CreateDirectory creates folders; Delete, Copy and Move manage files.
XML Serialization
Imports System.Xml.Serialization
<Serializable()>
Public Class Product
Public Property Name As String
Public Property Price As Decimal
End Class
Dim serializer As New XmlSerializer(GetType(Product))
Using sw As New StreamWriter("product.xml")
serializer.Serialize(sw, New Product With {.Name = "Book", .Price = 9.9})
End UsingThe XmlSerializer converts objects into XML and vice versa. The type must be serializable and have a parameterless constructor. Use Serialize and Deserialize.
Types and Extra Features
Anonymous Types
Dim person = New With {
.Name = "Anna",
.Age = 30
}
Console.WriteLine(person.Name) ' Anna
Console.WriteLine(person.Age) ' 30
' In LINQ:
Dim results = From n In {1, 2, 3, 4}
Select New With {.Number = n, .Double = n * 2}Anonymous types (New With { }) create objects without defining a class. They are useful in LINQ projections for temporary results with named properties.
Math (Mathematics)
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
The Math class has constants (PI, E) and functions like Abs, Pow, Sqrt, Round, Floor and Ceiling.
Specialized Collections
Imports System.Collections.Generic
' Queue (FIFO - first in, first out):
Dim queue As New Queue(Of String)
queue.Enqueue("A")
queue.Enqueue("B")
Console.WriteLine(queue.Dequeue()) ' A
' Stack (LIFO - last in, first out):
Dim stack As New Stack(Of Integer)
stack.Push(1)
stack.Push(2)
Console.WriteLine(stack.Pop()) ' 2Queue is a queue (FIFO) with Enqueue/Dequeue. Stack is a stack (LIFO) with Push/Pop. Choose according to the order you need.
Tuples
' Tuple with names:
Dim person = (Name:="Anna", Age:=30)
Console.WriteLine(person.Name) ' Anna
Console.WriteLine(person.Age) ' 30
' Return several values from a function:
Function Divide(a As Integer, b As Integer) As (Quotient As Integer, Remainder As Integer)
Return (a \ b, a Mod b)
End Function
Dim r = Divide(10, 3)
Console.WriteLine($"{r.Quotient} remainder {r.Remainder}") ' 3 remainder 1Tuples group several values without creating a class. With names (Name:=) the fields stay readable. They are ideal for returning multiple values from a function.
Random (Random Numbers)
Dim rnd As New Random() ' Random integer: Dim n = rnd.Next() ' 0 up to Integer.MaxValue Dim die = rnd.Next(1, 7) ' 1 to 6 ' Double between 0.0 and 1.0: Dim f = rnd.NextDouble() ' Fill a byte array: Dim bytes(15) As Byte rnd.NextBytes(bytes) ' Share an instance (avoids repetition): Shared ReadOnly Rnd As New Random()
The Random class generates random numbers. Next(min, max) returns an integer in the range (max exclusive). Reuse the instance to avoid repeated values.
Collection Conversions
Dim list As New List(Of Integer) From {1, 2, 3}
' List to Array:
Dim arr = list.ToArray()
' Array to List:
Dim list2 = arr.ToList()
' List to Dictionary:
Dim people = GetPeople()
Dim dict = people.ToDictionary(
Function(p) p.Id,
Function(p) p.Name)
' Filter into a new list:
Dim evens = list.Where(Function(n) n Mod 2 = 0).ToList()ToArray and ToList convert between collections. ToDictionary creates a dictionary from a list using functions for key and value.
Immutable Collections
Imports System.Collections.Immutable
Dim list = ImmutableList.CreateRange({1, 2, 3})
' "Changing" returns a new list:
Dim list2 = list.Add(4)
Console.WriteLine(list.Count) ' 3 (unchanged)
Console.WriteLine(list2.Count) ' 4
Dim dict = ImmutableDictionary(Of String, Integer).Empty
Dim dict2 = dict.Add("Anna", 30)Immutable collections (ImmutableList, ImmutableDictionary) never change: each operation returns a new collection. They are safe in concurrent code.
Guid (Unique Identifier)
' Generate a GUID:
Dim id = Guid.NewGuid()
Console.WriteLine(id) ' e.g.: 3f2a...-...-...
' As string without hyphens:
Dim s = id.ToString("N")
' Empty GUID:
Dim empty = Guid.Empty
Console.WriteLine(id = Guid.Empty) ' False
' Convert from string:
Dim g = Guid.Parse("3f2a1b...")Guid.NewGuid() generates a 128-bit globally unique identifier. It is used the a primary key and for unique names. Guid.Empty is the null value.
Advanced Conversions
' Enum to string and back:
Dim day = WeekDay.Friday
Dim name = day.ToString() ' "Friday"
Dim back = [Enum].Parse(GetType(WeekDay), "Friday")
' Byte array to Base64:
Dim bytes = {1, 2, 3, 4}
Dim b64 = Convert.ToBase64String(bytes)
Dim orig = Convert.FromBase64String(b64)
' Object to string:
Dim o As Object = 42
Dim s = Convert.ToString(o)Enum.Parse converts text into an enum. Convert.ToBase64String encodes bytes in Base64. The Convert class converts between various types.
TimeSpan
' Create a time interval:
Dim duration = New TimeSpan(1, 30, 0) ' 1h 30m
Console.WriteLine(duration.TotalMinutes) ' 90
' Factory methods:
Dim t = TimeSpan.FromHours(2)
Dim t2 = TimeSpan.FromSeconds(45)
' Difference between dates:
Dim start = #2024-01-01#
Dim finish = #2024-03-15#
Dim days = (finish - start).TotalDays
Console.WriteLine($"{days} days")TimeSpan represents a duration. TotalMinutes and TotalHours convert to units. The difference between two dates returns a TimeSpan.
Tips and Good Practices
Object Initializers
' Without constructor, setting properties:
Dim p As New Person With {
.Name = "Anna",
.Age = 30
}
' Collection with initializer:
Dim people As New List(Of Person) From {
New Person With {.Name = "Ray", .Age = 25},
New Person With {.Name = "Mia", .Age = 22}
}
Console.WriteLine(people.Count) ' 2The With { } block initializes properties when creating the object, without needing a constructor. It combines with From { } to fill collections in a readable way.
Defensive Handling
Sub Process(list As List(Of String))
' Validate arguments early:
If list Is Nothing Then
Throw New ArgumentNullException(NameOf(list))
End If
If list.Count = 0 Then Return
For Each item In list
If String.IsNullOrWhiteSpace(item) Then Continue For
Console.WriteLine(item.Trim())
Next
End SubValidate arguments at the start with ArgumentNullException. Use Return and Continue For to exit invalid cases early, keeping the main code free of nesting.
Coalescing and Elvis Operator
Dim name As String = Nothing ' If() with 2 args: first non-Nothing: Dim display = If(name, "Anonymous") ' Safe access with ?.: Dim length = name?.Length ' Nothing (no error) ' Useful combination: Dim size = name?.Length ?? -1 ' In VB you use a nested If: Dim size2 = If(name IsNot Nothing, name.Length, -1)
The ?. operator (null-conditional) only accesses the member if the object is not Nothing, avoiding NullReferenceException. If(a, b) does coalescing.
Repository Pattern (Example)
Public Interface IRepository(Of T)
Function GetById(id As Integer) As T
Function All() As List(Of T)
Sub Save(entity As T)
Sub Remove(id As Integer)
End Interface
Public Class CustomerRepository
Implements IRepository(Of Customer)
Public Function GetById(id As Integer) As Customer _
Implements IRepository(Of Customer).GetById
' access the DB...
Return New Customer()
End Function
End ClassThe Repository pattern abstracts data access behind a generic IRepository(Of T) interface. It eases testing and swapping the data source without changing the logic.
Dispose Pattern and IDisposable
Public Class Connection
Implements IDisposable
Private _open As Boolean = True
Public Sub Close()
If _open Then
_open = False
Console.WriteLine("Closed")
End If
End Sub
Public Sub Dispose() Implements IDisposable.Dispose
Close()
GC.SuppressFinalize(Me)
End Sub
End Class
' Usage with Using:
Using c As New Connection()
' ...
End UsingClasses with resources implement IDisposable with the Dispose method. The Using calls Dispose automatically, guaranteeing the release.
Singleton Pattern
Public Class Configuration
' Single instance, created thread-safe:
Private Shared ReadOnly _instance As New Lazy(Of Configuration)(
Function() New Configuration())
Public Shared ReadOnly Property Instance As Configuration
Get
Return _instance.Value
End Get
End Property
Private Sub New() ' private constructor
End Sub
Public Property Theme As String = "Light"
End Class
Dim cfg = Configuration.InstanceThe Singleton guarantees a single instance. The Private constructor prevents external creation and Lazy(Of T) creates the instance only when needed, in a thread-safe way.
Naming Conventions
' Classes, methods, properties: PascalCase
Public Class LoyalCustomer
Public Property FullName As String
Public Function CalculateDiscount() As Decimal
Return 0
End Function
End Class
' Local variables and parameters: camelCase
Dim purchaseTotal As Decimal
Sub Process(amount As Decimal)
End Sub
' Private fields: _camelCase
Private _balance As DecimalUse PascalCase for classes, methods and properties; camelCase for local variables and parameters; the _ prefix for private fields. Interfaces start with I.
General Best Practices
' 1. Option Strict On always
Option Strict On
' 2. Use Using for resources
Using conn = OpenConnection()
' ...
End Using
' 3. Prefer generic collections
Dim list As New List(Of Integer) ' not ArrayList
' 4. Async instead of blocking
Dim data = Await GetAsync() ' not .Result
' 5. Specific exceptions
Try
' ...
Catch ex As IOException
' handle
End TryEnable Option Strict On, use Using for resources, prefer generic collections, use Await instead of blocking and catch specific exceptions.