DevTools

Cheatsheet Visual Basic

Linguagem da Microsoft para aplicações Windows, Office e automação

Back to languages
Visual Basic
112 cards found
Categories:
Versions:

Basic and Structure


12 cards
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 Module

A 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 If

AndAlso 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 type

Option 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 Function

The 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 + 3

In 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


12 cards
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 Function

A 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 = 1

ByVal 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 Sub

A 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 Property

A 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 Function

Multi-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
Next

The 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)) ' 100

ParamArray 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 = 25

Local 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 55

A 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


12 cards
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")) ' 6

Strings 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  ' 1

The 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"))  ' negative

By 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


12 cards
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 Class

NotInheritable 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)   ' Wednesday

An 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 Class

Public 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 Class

An 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())  ' 5

A 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)  ' 2

Shared 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)  ' hello

Generics 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 Class

MustInherit 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 Class

Overloads 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 Class

Constraints (As Class, As New, As IComparable) limit the types accepted by a generic, allowing specific methods to be used safely.

Advanced


12 cards
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 Function

Async 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 Class

An 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}")
Next

Reflection (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 OnChangeHandler

AddHandler 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))  ' 12

A 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)     ' False

Use 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))  ' True

Func 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 If

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


12 cards
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
Loop

While...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 Select

The 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 > 0

When 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 Try

The 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)
Next

The 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 While

Continue 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 Using

The 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)}")
Next

The 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 Try

The 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


12 cards
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)  ' 5

An 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))           ' Ray

The 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)
Next

The 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 If

The 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()
Next

Multidimensional 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)
Next

When 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


10 cards
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 Using

ADO.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 Using

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

GetFiles 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 Using

ReadAllText 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)  ' Anna

JsonSerializer.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 Using

The 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


10 cards
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())  ' 2

Queue 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 1

Tuples 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


8 cards
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)  ' 2

The 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 Sub

Validate 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 Class

The 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 Using

Classes 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.Instance

The 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 Decimal

Use 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 Try

Enable Option Strict On, use Using for resources, prefer generic collections, use Await instead of blocking and catch specific exceptions.