VB.NET — Visual Basic .NET from Basics to Advanced (with C# Comparison)
In short: Both compile to the same IL and run on the same CLR with the same libraries, so performance is the same.
- Differences are syntax and features: VB.NET uses English-like keywords, is case-insensitive, line-based with
Endblocks, has XML literals,Mynamespace,WithEvents/Handlesand optional late binding; - C# uses C-style syntax, is case-sensitive and gets new language features every year while VB.NET has been feature-stable since 2020.
- Most new projects use C#; VB.NET is mainly maintained in legacy systems.
In short: Option Explicit On requires variables to be declared.
- Option Strict On disallows implicit narrowing conversions and late binding — catching type errors at compile time (strongly recommended).
- Option Infer On lets
Dim x = 5infer the type from the initializer. - Set them per project (Compile settings) or per file at the top.
In short: A Sub performs an action and returns no value (C# void method).
- A
Functionreturns a value withReturn(or by assigning to the function name in old code). - Both can take ByVal/ByRef, Optional and ParamArray parameters.
In short: ByVal (the default) passes a copy of the value — for reference types, a copy of the reference, so the method can modify the object but not replace the caller's variable.
- ByRef passes the variable itself, so assigning a new value inside the method changes the caller's variable (C#
ref).
static → Shared (and a Module is like a static class), this → Me, base → MyBase, null → Nothing, abstract class → MustInherit, abstract method → MustOverride, virtual → Overridable, override → Overrides, sealed → NotInheritable, internal → Friend.
Dim arr(5) As Integer create 6 elements?In short: VB.NET array declarations specify the upper bound, not the length, and arrays are zero-based — so arr(5) has indexes 0 to 5 = 6 elements.
- In C#,
new int[5]specifies the length (indexes 0–4). - A classic off-by-one source when converting code.
In short: And/Or always evaluate both operands (and also act as bitwise operators on integers).
AndAlso/OrElseshort-circuit: the second operand is evaluated only if needed.- Use
AndAlsofor conditions likeIf obj IsNot Nothing AndAlso obj.IsActive Thento avoid NullReferenceException.
In short: Declare with Event, raise with RaiseEvent.
- Subscribe statically by declaring the field
WithEventsand adding aHandles obj.EventNameclause to the handler (common in WinForms/Web Forms code-behind), or dynamically withAddHandler obj.Event, AddressOf HandlerandRemoveHandler(like C#+=/-=).
In short: DirectCast performs a type cast requiring an inheritance/interface relationship and throws InvalidCastException on failure (fast, like C# (T)x).
CTypeperforms any defined conversion including VB conversions (string to integer) and user-defined conversions.TryCastreturnsNothinginstead of throwing (reference types only, like C#as).
In short: On Error GoTo label / Resume Next is legacy unstructured error handling from VB6: errors jump to a label or are silently skipped, making flow hard to follow and hiding failures.
Try/Catch/Finallyis structured exception handling with typed exceptions, filters (When),Finallycleanup and proper rethrowing.- Use Try/Catch; refactor On Error when touching old code.
In short: A container whose members are implicitly Shared and which can't be instantiated or inherited — compiled as a sealed class with static members (C# static class).
- Module members can be called without qualifying the module name, which is convenient for helper functions and
Sub Main.
In short: A VB-only feature that lets you write XML directly in code as XElement/XDocument objects, embed expressions with <%= %>, and query with axis properties (.<child>, ...<descendant>, .@attribute).
- Handy for generating and reading XML configuration or reports with LINQ to XML.
In short: Yes.
- Each project compiles to IL in its own assembly, and projects reference each other normally (same CTS types).
- A single project can't mix languages.
- This makes gradual migration possible: put new code in C# libraries consumed by the VB application.
- Keep public APIs CLS-compliant (avoid names differing only by case, which VB can't distinguish).
In short: Yes for console, class libraries, WinForms and WPF (and Worker Services); the compiler is part of Roslyn.
- VB.NET won't get new language features, ASP.NET Core has no VB templates (you can still reference VB libraries from ASP.NET Core C# projects), and Web Forms stays on .NET Framework.
In short: Stabilise first: source control, Option Strict On, logging, tests on critical flows.
- Extract business logic from code-behind into class libraries (VB or new C#), target
netstandard2.0where possible so both old and new apps can use them. - Put a reverse proxy (YARP/IIS ARR) in front and rebuild pages/features in ASP.NET Core (C#) one area at a time, sharing authentication and the database (strangler fig).
- Retire Web Forms pages as their replacements go live.
In short: VB's classic string functions (Mid, InStr, Left) are 1-based, while .NET methods (Substring, IndexOf) are 0-based, and InStr returns 0 for "not found" while IndexOf returns −1.
- Converters sometimes translate them literally.
- Fix the indexes, add unit tests comparing old and new outputs for typical inputs.