Visual Basic .NET
Visual Basic .NET
Definition: Beginner-friendly, English-like language on the .NET platform, evolved from classic Visual Basic and still used for legacy and internal business tooling.
Paradigm: OOP | Typing: Static
Pros
- Easy to read and learn for developers and non-developers alike.
- Strong Windows, Office, and .NET integration.
- Useful for rapid internal tools and line-of-business applications.
- Good interop with the rest of the .NET ecosystem.
Cons
- Often perceived as outdated compared with C#.
- Community momentum is smaller and shrinking.
- Fewer new tutorials and less mindshare in modern .NET work.
- Outside Microsoft shops, the language is rarely a first choice.
Best For
- Internal business tools and legacy Windows automation.
- Maintaining older .NET applications and Office-adjacent scripts.
Real Examples
- Older enterprise Windows forms applications.
- Office automation and line-of-business internal tools.
Use Cases
- Internal line-of-business apps, WinForms utilities, and simple automation tools.
- Legacy system maintenance where the codebase already exists.
Extended Syntax & Features
Visual Basic .NET (VB.NET) was designed to be easy to learn, prioritizing English-like keywords over the curly braces and symbols common in C-style languages. Despite its conversational syntax, VB.NET is a fully featured, strongly-typed, object-oriented language that runs on the Common Language Runtime (CLR) of the .NET Framework.
Basic Data Types
VB.NET supports all standard .NET data types, using recognizable keywords:
Integer: A 32-bit signed integer.Long: A 64-bit signed integer.Short: A 16-bit signed integer.Double: A double-precision floating-point number.Decimal: A 128-bit data type suitable for financial calculations.Boolean: RepresentsTrueorFalse.String: A sequence of Unicode characters.Char: A single Unicode character.Date: Represents a date and time.Object: The root type from which all other types derive.
Variables are declared using the Dim keyword (short for Dimension):
Dim age As Integer = 30
Dim name As String = "Alice"
Dim isEmployed As Boolean = True
Dim salary As Decimal = 65000.5D
Control Flow
VB.NET provides traditional control flow structures, block-scoped by keywords like End If, Next, and End Select.
If-Then-Else:
If age >= 18 Then
Console.WriteLine("Adult")
ElseIf age >= 13 Then
Console.WriteLine("Teenager")
Else
Console.WriteLine("Child")
End If
Select Case (Switch statement equivalent):
Select Case dayOfWeek
Case 1
Console.WriteLine("Monday")
Case 6, 7
Console.WriteLine("Weekend")
Case Else
Console.WriteLine("Midweek")
End Select
Loops:
For ... NextFor Each ... Next(Iteration over collections)While ... End WhileDo While ... LooporDo Until ... Loop
For i As Integer = 1 To 5
Console.WriteLine("Iteration: " & i)
Next
For Each item In collection
Console.WriteLine(item.ToString())
Next
Functions and Methods
In VB.NET, subroutines that do not return a value are called Sub, and those that do return a value are called Function. Parameters can be passed ByVal (the default) or ByRef.
' A subroutine (no return value)
Sub PrintGreeting(ByVal name As String)
Console.WriteLine("Hello, " & name)
End Sub
' A function (returns a value)
Function CalculateArea(length As Double, width As Double) As Double
Return length * width
End Function
Classes and Object-Oriented Features
VB.NET is fully object-oriented, supporting inheritance, polymorphism, encapsulation, and abstraction.
- Classes are defined using
Class ... End Class. - Constructors are named
New. - Properties use getters and setters, though auto-implemented properties are common.
Public Class Person
Public Property Name As String
Public Property Age As Integer
Public Sub New(name As String, age As Integer)
Me.Name = name
Me.Age = age
End Sub
Public Overridable Sub Speak()
Console.WriteLine("Hello, I am " & Me.Name)
End Sub
End Class
Advanced Concepts
VB.NET leverages the robust architecture of the .NET framework, meaning its advanced concepts mirror those of C# and F#.
Memory Management and Garbage Collection
Memory management in VB.NET is handled automatically by the .NET Garbage Collector (GC). The GC allocates and deallocates memory for objects on the managed heap. While developers do not have to free memory manually, understanding the IDisposable interface and the Using statement is crucial for deterministically releasing unmanaged resources like file handles or database connections.
Using reader As New System.IO.StreamReader("file.txt")
Dim content As String = reader.ReadToEnd()
Console.WriteLine(content)
End Using ' The reader is automatically disposed here.
Concurrency and Asynchronous Programming
Modern VB.NET natively supports the Task-based Asynchronous Pattern (TAP) via the Async and Await keywords. This allows developers to write non-blocking code that looks synchronous, avoiding callback hell and UI-freezing.
Public Async Function FetchDataAsync(url As String) As Task(Of String)
Using client As New HttpClient()
' Await suspends the execution until the network request completes
Dim response As String = Await client.GetStringAsync(url)
Return response
End Using
End Function
Generics
Generics allow you to define classes, interfaces, and methods with placeholders for the types they store or use. This improves type safety and performance by avoiding boxing and unboxing of value types. In VB.NET, generics are denoted using the (Of T) syntax.
' A generic class
Public Class GenericBox(Of T)
Private _item As T
Public Sub SetItem(item As T)
_item = item
End Sub
Public Function GetItem() As T
Return _item
End Function
End Class
Language-Integrated Query (LINQ)
One of the most powerful features of VB.NET is its deep integration with LINQ. VB.NET provides query comprehension syntax that closely resembles SQL, often making it more expressive for database queries and data manipulation than its C# counterpart.
Dim numbers As Integer() = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
Dim evens = From num In numbers
Where num Mod 2 = 0
Select num
For Each n In evens
Console.WriteLine(n)
Next
Late Binding and Dynamic Typing
Due to its legacy and COM interop requirements, VB.NET supports late binding. By default (if Option Strict is Off), you can call methods on Object types at runtime. While this introduces flexibility similar to dynamic languages, it sacrifices compile-time type safety. It is strongly recommended to set Option Strict On to prevent unintended late binding.
Ecosystem & Tooling
Because VB.NET is a first-class citizen of the .NET platform (though it has taken a backseat to C# in recent years), it enjoys access to the vast .NET ecosystem.
Tooling
- Visual Studio: The premier IDE for VB.NET. It offers unparalleled features for VB.NET, including background compilation, a rich WinForms drag-and-drop designer, and extensive refactoring tools.
- .NET CLI: The
dotnetcommand-line tool can create, build, and run VB.NET projects (dotnet new console -lang vb). - MSBuild: The build engine used under the hood to compile VB.NET projects into MSIL (Microsoft Intermediate Language).
Package Managers
- NuGet: The standard package manager for all .NET languages. Any library written in C# and published on NuGet can be seamlessly consumed in a VB.NET project.
Frameworks and Environments
- .NET Core / .NET 5+: While Microsoft has stated that VB.NET will not evolve as rapidly as C# going forward, it is fully supported in modern .NET for console applications, class libraries, and web APIs.
- Windows Forms (WinForms) & WPF: The traditional bread-and-butter for VB.NET, heavily used for building thick-client Windows desktop applications.
- ASP.NET: Historically, VB.NET was widely used in ASP.NET Web Forms. While still possible in ASP.NET Core, it’s far less common for new web projects.
Standard Libraries
VB.NET uses the Base Class Library (BCL) of .NET (System.* namespaces). In addition, it includes the Microsoft.VisualBasic namespace, which provides compatibility functions and unique features like My namespace (My.Computer, My.Application) that offer simplified access to the OS, network, and application state.
Code Examples
1. Hello World
The classic introductory program. VB.NET uses a Module or a Class containing a Main subroutine as the entry point.
' Program.vb
Imports System
Module Program
Sub Main()
' Prints a message to the console
Console.WriteLine("Hello, World!")
' Wait for user input before closing
Console.ReadLine()
End Sub
End Module
2. Data Structures and Collections
Working with .NET generic collections is strongly typed and safe. Here we use a List(Of T) and a Dictionary(Of TKey, TValue).
Imports System.Collections.Generic
Module CollectionsExample
Sub Main()
' Using a generic List
Dim fruits As New List(Of String)()
fruits.Add("Apple")
fruits.Add("Banana")
fruits.Add("Cherry")
Console.WriteLine("--- List of Fruits ---")
For Each fruit In fruits
Console.WriteLine(fruit)
Next
' Using a generic Dictionary
Dim ages As New Dictionary(Of String, Integer)()
ages.Add("Alice", 28)
ages.Add("Bob", 35)
Console.WriteLine(vbCrLf & "--- Dictionary of Ages ---")
For Each kvp In ages
Console.WriteLine($"{kvp.Key} is {kvp.Value} years old.")
Next
End Sub
End Module
3. Object-Oriented Programming
Demonstrating inheritance, method overriding, and polymorphism.
Public MustInherit Class Animal
Public Property Name As String
Public Sub New(name As String)
Me.Name = name
End Sub
' An abstract method that must be implemented by derived classes
Public MustOverride Sub MakeSound()
End Class
Public Class Dog
Inherits Animal
Public Sub New(name As String)
MyBase.New(name)
End Sub
Public Overrides Sub MakeSound()
Console.WriteLine($"{Name} says: Woof!")
End Sub
End Class
Public Class Cat
Inherits Animal
Public Sub New(name As String)
MyBase.New(name)
End Sub
Public Overrides Sub MakeSound()
Console.WriteLine($"{Name} says: Meow!")
End Sub
End Class
Module OOPExample
Sub Main()
Dim myPets As New List(Of Animal) From {
New Dog("Buddy"),
New Cat("Whiskers")
}
For Each pet In myPets
pet.MakeSound()
Next
End Sub
End Module
4. File I/O and Exception Handling
Reading and writing files while properly handling potential errors using Try...Catch...Finally.
Imports System.IO
Module FileIOExample
Sub Main()
Dim filePath As String = "test.txt"
' Writing to a file
Try
Using writer As New StreamWriter(filePath)
writer.WriteLine("This is the first line.")
writer.WriteLine("This is the second line.")
End Using
Console.WriteLine("Data successfully written to file.")
Catch ex As UnauthorizedAccessException
Console.WriteLine("Error: You do not have permission to write to this file.")
Catch ex As Exception
Console.WriteLine($"An unexpected error occurred: {ex.Message}")
End Try
' Reading from a file
Try
If File.Exists(filePath) Then
Using reader As New StreamReader(filePath)
Dim content As String = reader.ReadToEnd()
Console.WriteLine(vbCrLf & "File Content:")
Console.WriteLine(content)
End Using
Else
Console.WriteLine("Error: File does not exist.")
End If
Catch ex As Exception
Console.WriteLine($"Failed to read file: {ex.Message}")
Finally
Console.WriteLine("File IO operations completed.")
End Try
End Sub
End Module
5. Asynchronous Network Request
Using HttpClient and the Async/Await pattern to fetch data from an API without blocking the main thread.
Imports System.Net.Http
Imports System.Threading.Tasks
Module NetworkExample
' Main can be Async in modern .NET versions
Async Function Main() As Task
Dim apiUrl As String = "https://jsonplaceholder.typicode.com/todos/1"
Console.WriteLine("Fetching data from API...")
Try
Dim result As String = Await FetchDataAsync(apiUrl)
Console.WriteLine(vbCrLf & "Response received:")
Console.WriteLine(result)
Catch ex As HttpRequestException
Console.WriteLine($"Network error: {ex.Message}")
End Try
End Function
Async Function FetchDataAsync(url As String) As Task(Of String)
Using client As New HttpClient()
' Asynchronously send a GET request
Dim response As HttpResponseMessage = Await client.GetAsync(url)
' Ensure the request was successful
response.EnsureSuccessStatusCode()
' Asynchronously read the response body as a string
Dim responseBody As String = Await response.Content.ReadAsStringAsync()
Return responseBody
End Using
End Function
End Module
6. Functional Features with LINQ
LINQ queries allow for declarative data manipulation. VB.NET has excellent syntactical support for LINQ.
Imports System.Linq
Module LinqExample
Class Employee
Public Property Id As Integer
Public Property Name As String
Public Property Department As String
Public Property Salary As Decimal
End Class
Sub Main()
Dim employees As New List(Of Employee) From {
New Employee With {.Id = 1, .Name = "Alice", .Department = "IT", .Salary = 75000},
New Employee With {.Id = 2, .Name = "Bob", .Department = "HR", .Salary = 60000},
New Employee With {.Id = 3, .Name = "Charlie", .Department = "IT", .Salary = 85000},
New Employee With {.Id = 4, .Name = "Diana", .Department = "Finance", .Salary = 90000}
}
' Query syntax (similar to SQL)
Dim itEmployees = From emp In employees
Where emp.Department = "IT"
Order By emp.Salary Descending
Select emp.Name, emp.Salary
Console.WriteLine("IT Department Employees (Ordered by Salary):")
For Each emp In itEmployees
Console.WriteLine($"{emp.Name} - {emp.Salary:C}")
Next
' Method syntax (Fluent API)
Dim averageSalary = employees.Average(Function(e) e.Salary)
Console.WriteLine(vbCrLf & $"Average Company Salary: {averageSalary:C}")
End Sub
End Module
Best Practices
To write maintainable and robust VB.NET code, the community and Microsoft recommend several best practices:
1. Enforce Strict Typing (Option Strict On)
By default, VB.NET allows implicit type conversions and late binding, a relic of classic VB. This can lead to runtime errors that could have been caught at compile time.
Rule: Always enable Option Strict On in your project settings. This forces explicit casting and enforces type safety.
' With Option Strict On, this is illegal:
' Dim obj As Object = "Hello"
' Dim length As Integer = obj.Length ' Compiler Error
' Instead, do this:
Dim str As String = "Hello"
Dim length As Integer = str.Length
2. Avoid Legacy VB6 Functions
VB.NET includes the Microsoft.VisualBasic namespace for backward compatibility (e.g., MsgBox(), CInt(), Len(), Mid()).
Rule: Use modern .NET Framework equivalents instead. It makes code more uniform with the rest of the .NET ecosystem.
- Instead of
MsgBox(), useMessageBox.Show()(in WinForms). - Instead of
Len(str), usestr.Length. - Instead of
Mid(str, 1, 5), usestr.Substring(0, 5). - Instead of
CInt(val), useConvert.ToInt32(val)orInteger.Parse(val).
3. Use String.Format or String Interpolation
String concatenation using & can become messy and unreadable. Modern VB.NET supports string interpolation, making string construction cleaner.
Dim name As String = "John"
Dim age As Integer = 30
' Avoid:
Dim message1 = "My name is " & name & " and I am " & age & " years old."
' Better (String.Format):
Dim message2 = String.Format("My name is {0} and I am {1} years old.", name, age)
' Best (Interpolation):
Dim message3 = $"My name is {name} and I am {age} years old."
4. Properly Dispose of Resources
Whenever working with unmanaged resources (database connections, file streams, network sockets), ensure they are closed.
Rule: Always use the Using statement for objects that implement IDisposable. This guarantees Dispose() is called even if an exception occurs.
' The connection is guaranteed to be closed when exiting the block
Using conn As New SqlConnection(connectionString)
conn.Open()
' Execute queries
End Using
5. Favor Generic Collections over Arrays or Legacy Collections
Legacy collections like ArrayList or HashTable are weakly typed (store Object), leading to boxing/unboxing overhead and runtime type errors.
Rule: Use generic collections from System.Collections.Generic (e.g., List(Of T), Dictionary(Of TKey, TValue)). They are strongly typed and more performant.
6. Avoid “Catch Everything” Blocks
Swallowing exceptions without proper logging or handling makes debugging nearly impossible.
Rule: Catch specific exceptions when possible. If you must catch a general Exception, at least log it. Never leave an empty Catch block.
Try
' risky code
Catch ex As FileNotFoundException
' Handle specifically
Console.WriteLine("File not found: " & ex.FileName)
Catch ex As Exception
' Log and/or rethrow
Logger.LogError(ex)
Throw
End Try
7. Name Conventions
Follow standard .NET naming conventions:
- PascalCase for Classes, Methods, Properties, and Namespaces.
- camelCase for local variables and method parameters.
- _camelCase for private class-level fields.
Public Class CustomerService
Private _customerRepository As ICustomerRepository ' Private field
Public Sub New(customerRepository As ICustomerRepository) ' Parameter
_customerRepository = customerRepository
End Sub
Public Function GetCustomerName(customerId As Integer) As String ' Method and PascalCase
Dim customerName As String = _customerRepository.GetName(customerId) ' Local variable
Return customerName
End Function
End ClassReferenced by