C To Vb.net

VB/C# .Net Code Converter is a free and simple VB to C# and C# to VB code converter. This online tool allows you to convert entire class code or selected section of code snippets.

Bookmark:

  • VB.NET forum discussion. ICSharp ZIP library C# to VB.NET Port by Garry Wang (6 replies) Printing with formatting in VB.NET by jclebon (7 replies) IP2Location Geolocation.NET Component in VB.NET by dunking (5 replies) Watching Folder Activity in VB.NET by emmaddai (17 replies) print a document file without using print dialog control in Vb.net.
  • Adds context menu items to convert projects/files between VB.NET and C#. See the wiki documentation for help using it. Download from Visual Studio Marketplace (Requires VS 2017 15.7+) Flexible: Convert a small selection, or a whole solution in one go, in either direction.

C#5.0 Hi Is there any free tool available in on-line or offline (exe format install in local machine) to convert whole project form C# to vb.net,no need single page convector,need full project,may be browser project folder or project zip file and output project save in one folder.

This online code conversion tool powered by open source NRefactory library. NRefactory is a powerful C# to VB and VB to C# conversion engine maintained by the developers at SharpDevelop. By default, NRefactory may requires that all code be properly wrapped in a class and (as necessary) method before converting.

Features of Visual Basic .NET not found in C#

  • Variables can be declared using the WithEvents construct. This construct is available so that a programmer may select an object from the Class Name drop down list and then select a method from the Declarations drop down list to have the Method signature automatically inserted
  • Auto-wireup of events, VB.NET has the Handles syntax for events
  • Marshalling an object for multiple actions using an unqualified dot reference. This is done using the With ... End With structure
  • IsNumeric evaluates whether a string can be cast into a numeric value (the equivalent for C# requires using int.TryParse)
  • XML Literals
  • Inline date declarations by using #1/1/2000# syntax (M/dd/yyyy).
  • Module (although C#'s sealed static classes with additional semantics, but each field has to individually be declared as static)
  • Members of Modules imported to the current file, can be access with no preceeding container accessor (See Now for example)
  • The My namespace
  • Visual Studio's design-time experience is more responsive in the VB.NET language
  • COM components and interoperability is more powerful in VB.NET as the Object type is bound at runtime
  • Namespaces can be important in project level, so they don't have to be imported to each individual file, like C#
  • Root namespace, in VB.NET projets, you can set the assembly root namespace which the whole project is wrapped with it, and you don't have to declare the namespace for each container.

Features of C# not found in Visual Basic .NET

  • Allows blocks of unsafe code (like C++/CLI) via the unsafe keyword.
  • Partial Interfaces
  • Iterators and the yield keyword
  • Multi-line comments (note that the Visual Studio IDE supports multi-line commenting for Visual Basic .NET)
  • Static classes (Classes which cannot contain any non-static members, although VB's Modules are essentially sealed static classes with additional semantics)
  • Can use checked and unchecked contexts for fine-grained control of overflow/underflow checking

Other characteristics of Visual Basic .NET not applicable to C#

  • Conversion of Boolean value True to Integer may yield -1 or 1 depending on the conversion used
  • Assigning and comparing variables uses the same token, =. Whereas C# has separate tokens, for comparison and = to assign a value
  • VB.NET is not case-sensitive.
  • Type checking is less strict by default. If the default is left in place, It will auto convert type without notifying programmer
  • Val() function which also parses a null value while converting into double (In c# Convert.ToDouble() is used to convert any object into double type value, but which throws exception in case of a null value)
  • CInt, CStr, CByte and a wide variety of converting functions built in the language

Other characteristics of C# not applicable to Visual Basic .NET

  • By default, numeric operations are not checked. This results in slightly faster code, at the risk that numeric overflows will not be detected. However, the programmer can place arithmetic operations into a checked context to activate overflow checking. (It can be done in Visual Basic by checking an option)
  • Addition and string concatenation use the same token, +. Visual Basic .NET, however, has separate tokens, + for addition and & for concatenation, although + can be used for concatenation as well.
  • In Visual Basic .NET property methods may take parameters
  • C# is case-sensitive.

External Resources:

Equivalents were produced with Instant C# and Instant VB.

VB.NETC#
Public MustInherit Class AbstractClass
Protected MustOverride Sub AbstractMethod()
End Class
public abstract class AbstractClass
{
protected abstract void AbstractMethod();
}
VB.NETC#
Public
Private
Friend
Protected
Protected Friend
public
private
internal
protected
protected internal

Unsized Array

VB.NETC#
Dim myArray() As Integer int[] myArray = null;

Sized Array

VB.NETC#
Dim myArray(1) As Integer int[] myArray = new int[2];

Access Array Element

VB.NETC#
x = myArray(0) x = myArray[0];

C# To Vb.net Format

Jagged Array

VB.NETC#
Dim myArray(1)() As Integer int[][] myArray = new int[2][];

Rectangular Array

VB.NETC#
Dim myArray(1, 2) As Integer int[,] myArray = new int[2, 3];

Resizing Array

VB.NETC#
ReDim Preserve myArray(newSize)
ReDim myArray(newSize)
System.Array.Resize(ref myArray, newSize + 1);
myArray = new foo[newSize + 1];

C# To Vb.net Login

Initializing Array

VB.NETC#
myArray = New Integer(1) {1,2} myArray = new int[2] {1, 2};

Empty Array

VB.NETC#
Dim myArray As String() = New String() {} string[] myArray = new string[0];

Class Attribute

VB.NETC#
<Serializable()>
Public Class Foo
[Serializable()]
public class Foo

Method Attribute

Vb.net
VB.NETC#
<DebuggerHidden()>
Public Sub Method()
[System.Diagnostics.DebuggerHidden()]
public void Method()

Method Return Type Attribute

VB.NETC#
Public Function Method() As <ReturnAttribute> Integer [return: ReturnAttribute]
public int TestReturnValueAttribute()

Method Parameter Attribute

VB.NETC#
Public Sub Method(<ParamAttribute> ByVal x As Integer) public void Method([ParamAttribute] int x)

Named Properties in Attributes

Attributes have a special syntax which allows setting properties of the attribute type after the attribute constructor arguments - called named properties. These have the same syntax as named arguments in VB, but not in C#. Note that in the following example, 'property1' and 'property2' are named properties, not named arguments - the attribute type constructor for this example would only have one parameter, not three. Named arguments are not available for attributes.

VB.NETC#
'note: property1 and property2 are named properties:
<FooAttribute(arg, property1:=1, property2:=2)>
Public Class Foo
End Class
//note: property1 and property2 are named properties:
[FooAttribute(arg, property1=1, property2=2)]
public class Foo
{
}

AutoEventWireup is an ASP.NET page attribute that will allow automatic wireup of page events when this attribute is set to true on the page. The AutoEventWireup page attribute leads to the following options for the associated VB and C# code-behind class:

AutoEventWireup = true

This allows specifying Page_Load, Page_Init, etc. event handler methods by name alone. In VB, no Handles clause is appended and in C# no event wireup code is required. Provided the method name matches, the methods will automatically handle the associated events. If you do erroneously code any event wireup code, this will cause the event handler to execute twice.

AutoEventWireup = false

This requires that you code the event handler wireup. In VB, you would specify a Handles clause and in C# you would include code to subscribe to the events. However, in C# the problem is that the first page event occurs before the event wireup code has a chance to execute. A common C# approach in this case is to override the base class OnLoad, OnInit, etc. methods, dispensing with the need to have event handler wireup code for the page events. For these cases (Handles used instead of setting AutoEventWireup to true), Instant C# automatically adds event wireups corresponding to all 'Page' methods where a Handles clause is used to the Page_Init or OnInit method if it exists. If no Page_Init or OnInit method exists, a new OnInit method is added. The event wireup for the Page_Init method is added to the class constructor - if no constructor exists, then a constructor is added by Instant C#.

VB.NETC#
Sub Method1(ByRef myParam As Integer)
End Sub
Sub Method2
Method1(foo)
End Sub
void Method1(ref int myParam)
{
}
void Method2()
{
Method2(ref foo); //'ref' is required in the method call also
}

The closest equivalent to the standard VB casting operators (CType and the corresponding CInt, CStr, etc.) are calls to the System.Convert methods if the appropriate method exists, otherwise they are converted to the standard C# casting operator.
The behavior of both the System.Convert methods and the standard C# casting operator are subtly different from the VB casting operators though, so you should always test the behavior of your converted code.
The C# equivalent to VB's 'DirectCast' is the standard C# casting operator.
The VB 'TryCast' operator always converts to the C# 'as' operator. The C# 'as' operator converts to the VB 'TryCast' operator, except for the case of nullable types, in which case you must use the 'CType' operator.

VB.NETC#

x = CBool(y)
x = CInt(y)
x = CDec(y)
x = CChar(y)
x = CStr(y)
x = CDate(y)
x = CObj(y)
x = CType(y, Foo)
x = DirectCast(y, Foo)
x = TryCast(y, Foo)
using System;
x = Convert.ToBoolean(y);
x = Convert.ToInt32(y);
x = Convert.ToDecimal(y);
x = Convert.ToChar(y);
x = Convert.ToString(y);
x = Convert.ToDateTime(y);
x = (object)y;
x = (Foo)y;
x = (Foo)y;
x = y as Foo;

A further complication is that C# integer casts always truncate, while the VB integer conversion operators always round. For this reason, in order to achieve the same results as the C# casts, a call to the .NET Math.Truncate function is required prior to the call to the CInt, CLng, and CShort operators when converting C# integer casts.

C#VB.NET
i = (int)someDouble; i = CInt(Math.Truncate(someDouble))

In VB, the keyword 'From' is used to initialize collections during construction.

VB.NETC#
'lists:
Dim myList As New List(Of Integer)() From {1, 2, 3}
'dictionaries:
Dim myD As New Dictionary(Of String, Integer) From {
{string1, 80},
{string2, 85}
}
//lists:
List<int> myList = new List<int>() {1, 2, 3};
//dictionaries:
Dictionary<string, int> myD = new Dictionary<string, int>() {
{string1, 80},
{string2, 85}
};

Unlike VB's #Const, C# #define's cannot set values - they always specify 'true'.

VB.NETC#
#Const ONE = True
#Const TWO = 2
#If ONE Then
'code for condition ONE
#ElseIf TWO Then
'code for condition TWO
#Else
'code for other cases
#End If
#define ONE
//#Const TWO = 2 - no C# equivalent
#if ONE
//code for condition ONE
#elif TWO
//code for condition TWO
#else
//code for other cases
#endif

Local Constant

VB.NETC#
Const myConst As Integer = 2 const int myConst = 2;

Local Variable

VB.NETC#
Dim myVar As Integer = 2 int myVar = 2;

Inferred Types

VB.NETC#
Option Infer On
...
Dim myVar = 2
var myVar = 2;

Shared/Static Field

VB.NETC#
Public Shared S As Integer public static int S;

Read-Only Field

VB.NETC#
Public ReadOnly R As Integer = 2 public readonly int R = 2;

VB Static Local Variable

VB.NETC# (no direct equivalent)
Sub Method()
Static s As Integer
s += 1
End Sub
private int Method_s;
void Method()
{
Method_s += 1;
}
VB.NETC#
Class Foo
Public Sub New()
Me.New(0) 'call to other constructor
End Sub
Public Sub New(ByVal i As Integer)
End Sub
Protected Overrides Sub Finalize()
End Sub
End Class
class Foo
{
public Foo() : this(0) //call to other constructor
{
}
public Foo(int i)
{
}
~Foo()
{
}
}
VB.NETC#
Integer
Boolean
String
Char
Single
Double
Date
Object
Decimal
Short
Long
Byte
SByte
UShort
UInteger
ULong
int
bool
string
char
float
double
System.DateTime (no C# language type)
object
decimal
short
long
byte
sbyte
ushort
uint
ulong
VB.NETC#
Public Delegate Sub FooDelegate() public delegate void FooDelegate();

Implicitly-Typed Enum

VB.NETC#
Public Enum FormMode
EditMode
NewMode
End Enum
public enum FormMode
{
EditMode,
NewMode
}

Explicitly-Typed Enum

VB.NETC#
Public Enum FormMode As Byte
EditMode
NewMode
End Enum
public enum FormMode : byte
{
EditMode,
NewMode
}

Event Declarations

C To Vb.net
VB.NETC#
Public Event EventOne(ByVal p As Foo) 'implicit delegate
Public Event EventTwo As FooDelegate 'explicit delegate
public delegate void EventOneEventHandler(Foo p);
public event EventOneEventHandler EventOne;
public event FooDelegate EventTwo;

Event Wireups

VB.NETC#
AddHandler ControlA.Click, New ControlA.SomeEventHandler(AddressOf ControlA_Click)
AddHandler ControlA.Click, AddressOf ControlA_Click
ControlA.Click += new ControlA.SomeEventHandler(ControlA_Click);
ControlA.Click += ControlA_Click;

Strict Conversion of WithEvents/Handles

VB.NETC#
Class TestClass
Private WithEvents MyField As FooDelegate
Sub Method() Handles MyField.FooEvent
End Sub
End Class
using System.Runtime.CompilerServices;
using System.Diagnostics;
class TestClass
{
[AccessedThroughProperty(nameof(MyField))]
private FooDelegate _MyField;
private FooDelegate MyField
{
[DebuggerNonUserCode]
get
{
return _MyField;
}
[MethodImpl(MethodImplOptions.Synchronized), DebuggerNonUserCode]
set
{
if (_MyField != null)
_MyField.FooEvent -= Method;
_MyField = value;
if (value != null)
_MyField.FooEvent += Method;
}
}
void Method()
{
}
}

Casual Conversion of WithEvents/Handles

VB.NETC#
Class TestClass
Private WithEvents MyField As FooDelegate
Sub Method() Handles MyField.FooEvent
End Sub
End Class
class TestClass
{
private FooDelegate MyField;
void Method()
{
}
public TestClass()
{
SubscribeToEvents();
}
private bool EventsSubscribed = false;
private void SubscribeToEvents()
{
if (EventsSubscribed)
return;
else
EventsSubscribed = true;
MyField.FooEvent += Method;
}
}
VB.NETC#
Try
...
Catch x As FooException
...
Catch y As BarException When z = 1
...
Finally
...
End Try
try
{
...
}
catch (FooException x)
{
...
}
catch (BarException y) when (z 1)
{
...
}
finally
{
...
}

VB extension methods are declared in modules and use the 'Extension' attribute, while C# extension methods are declared in static classes and use the 'this' keyword on the first parameter.

VB.NETC#
Public Module Foo
<System.Runtime.CompilerServices.Extension> _
Sub Extension(ByVal myParam As String)
'...
End Sub
End Module
public static class Foo
void Extension(this string myParam)
{
//...
}
}

Creating a List

VB.NETC#
Dim myVar As New List(Of Integer) List<int> myVar = new List<int>();

Creating a Dictionary

VB.NETC#
Dim myVar As New Dictionary(Of String, Integer) Dictionary<string, int> myVar = new Dictionary<string, int>();

Defining a Generic Class

VB.NETC#
Public Class GenericClass (Of T)
End Class
public class GenericClass<T>
{
}

Defining a Generic Class with a Constraint

VB.NETC#
Public Class GenericClass (Of T As SomeBase)
End Class
public class GenericClass<T> where T: SomeBase
{
}

Defining a Generic Class with a 'new' Constraint

VB.NETC#
Public Class GenericClass (Of T As New)
End Class
public class GenericClass<T> where T: new()
{
}

Defining a Generic Method

VB.NETC#
Public Function Compare(Of T)(param1 As T, param2 As T) As Integer
End Function
public int Compare<T>(T param1, T param2)
{
}

Defining a Generic Method with a Constraint

C3 To Vb.net

VB.NETC#
Sub Swap(Of T As Class)(ByRef l As T, ByRef r As T)
End Sub
void Swap<T>(ref T l, ref T r) where T: class
{
}
VB.NETC#
Imports Foo
Imports Foo.Bar 'Bar' is a type
'namespace alias:
Imports foo = SomeNamespace
'type alias:
Imports bar = SomeNamespace.SomeType
using Foo;
using static Foo.Bar; //'Bar' is a type
//namespace alias:
using foo = SomeNamespace;
//type alias:
using bar = SomeNamespace.SomeType;

Basic Inheritance

VB.NETC#
Class Foo
Inherits SomeBase
End Class
class Foo : SomeBase
{
}

Inheritance Keywords

VB.NETC#
MustInherit (class)
MustOverride (method)
Overrides (method)
NotInheritable (class)
NotOverridable (method)
Shadows (member)
abstract (class)
abstract (method)
override (method)
sealed (class)
sealed (method)
new (member)

Defining Interfaces

VB.NETC#
Public Interface IFoo
Sub Method()
End Interface
public interface IFoo
{
void Method();
}

Implementing Interfaces

VB.NETC#
Public Class Foo
Implements IFoo
Public Sub Method() Implements IFoo.Method
End Sub
End Class
*note that you can use a method name which does not match the interface method name, provided that the 'Implements' name matches
//implicit implementation:
public class Foo : IFoo
{
public void Method()
{
}
}
or:
//explicit implementation:
public class Foo : IFoo
{
void IFoo.Method()
{
}
}

Expression Lambda

VB.NETC#
myVar = Function(text As String) text.Length myVar = (string text) => text.Length;

Multi-statement Lambda

VB.NETC#
myVar = Function(text As String)
Return text.Length
End Function
myVar = (string text) =>
{
return text.Length;
}

Event Wireup with Lambda

VB.NETC#
AddHandler button.Click, Sub(src, e) Log(src, e) button.Click += (src, e) => Log(src, e);

VB uses the 'CreateObject' function to acquire a type instance at run-time where the type is unknown at compile time. VB then allows invoking members of this instance even though the type is unknown at compile time (this requires the VB Option Strict setting to be turned off). C# allows the same behavior via the 'dynamic' keyword and a call to System.Activator.CreateInstance:

VB.NETC#
Option Strict Off
...
Dim o As Object = CreateObject(progID)
o.Foo() 'late-bound call to 'Foo' method
dynamic o = System.Activator.CreateInstance(System.Type.GetTypeFromProgID(progID));
o.Foo(); //late-bound call to 'Foo' method
VB.NETC#
Dim payingCustomers = From c In db.Customers
Where c.Orders.Count > 0
Select c.Email, c.Name
var payingCustomers = from c in db.Customers
where c.Orders.Count > 0
select new {c.Email, c.Name};

For Loop

VB.NETC#
For i As Integer = 1 To 9
Next i
for (int i = 1; i <= 9; i++)
{
}

For Each Loop

VB.NETC#
For Each s As String In StringList
Next s
foreach (string s in StringList)
{
}

While Loop

VB.NETC#
Do While condition
Loop
or:
While condition
End While
while (condition)
{
}

Do While Loop

VB.NETC#
Do
Loop While condition
do
{
} while (condition);

Loop Until

VB.NETC# (no specific 'loop until' construct)
Do
Loop Until condition
do
{
} while ( ! condition);

Do Until

VB.NETC# (no specific 'do until' construct)
Do Until condition
Loop
while ( ! condition)
{
}
VB.NETC#
Public Module Utility
Public Sub UtilityMethod()
...
End Sub
End Module
or:
Public NotInheritable Class Utility
Private Sub New() 'prevent instantiation
End Sub
Public Shared Sub UtilityMethod()
...
End Sub
End Class
public static class Utility
{
public static void UtilityMethod()
{
...
}
}
VB.NET (2015 multiline string)C# (verbatim string)
Dim myVar = 'first line
second line'
var myVar = @'first line
second line';

Inequality tests in VB using the '<>' operator involving nullable types (System.Nullable with a struct type parameter) behave very differently from the same tests in C# using the '!=' operator. In VB, if the nullable value is 'Nothing', then the conditional always evaluates to 'Nothing', which has the same effect as the conditional being 'False'. In C#, if the nullable value is 'null', then the conditional evaluates to 'true' when comparing to a non-null value.

The root of the inconsistency between VB and C# is that the ' and '!=' operators are interpreted in C# exactly as if you were calling the System.Nullable 'Equals' method, while the VB '=' and '<>' operators are not, instead relying on the unusual VB language rules. To get the expected conditional results, the correct VB approach would be to use the System.Nullable 'Equals' method.

VBC#
Dim nullInt As Integer? = Nothing
If nullInt <> 0 Then
'statement doesn't execute!
MessageBox.Show('not equal')
End If
int? nullInt = null;
if (nullInt != 0)
//statement executes as expected
MessageBox.Show('not equal');

The following C# reproduces the VB behavior:

C#
int? nullInt = null;
if (nullInt.HasValue && nullInt != 0)
//statement doesn't execute
MessageBox.Show('not equal');

The following VB is a better approach and is equivalent to our original C# code:

VBC#
Dim nullInt As Integer? = Nothing
If Not nullInt.Equals(0) Then
'statement executes as expected
MessageBox.Show('not equal')
End If
int? nullInt = null;
if (nullInt != 0)
//statement executes as expected
MessageBox.Show('not equal');

Note that you can call a method on a 'null' System.Nullable instance without throwing an exception since nullable instances are never null like reference types are null. Instead, they are generic value types with no value set.

Named Type Object Initializer

VB.NETC#
Dim myVar = New Person() With
{
.Name = s1,
.Surname = s2
}
var myVar = new Person()
{
Name = s1,
Surname = s2
};

Anonymous Type Object Initializer

VB.NETC#
Dim myVar = New With
{
.Name = x,
.Surname = y
}
var myVar = new
{
Name = x,
Surname = y
};
C to vb.net code converter
VB.NETC#
Public Shared Operator *(ByVal X As SomeType, ByVal Y As SomeType) As Long
'...
End Operator
Public Shared Narrowing Operator CType(ByVal X As SomeType) As SomeOtherType
'...
End Operator
Public Shared Widening Operator CType(ByVal X As SomeOtherType) As SomeType
'...
End Operator
public static long operator * (SomeType X, SomeType Y)
{
//...
}
public static explicit operator SomeOtherType(SomeType X)
{
//...
}
public static implicit operator SomeType(SomeOtherType X)
{
//...
}
VB.NETC#
+, -, *, >, >=, <, <=, <<, >>
& (string concatenation)
() (indexing)
And
Or
AndAlso
OrElse
Not
Xor
Mod
x ^ y
=
Is
IsNot
<>
If(x, y, z)
If(x, y)
x / y (where x and y are integers)
x / y (where x and y are doubles)
x y (where x and y are integers)
x y (where x and y are doubles)
unchanged
+ (string concatenation)
[]
&
|
&&
||
! or ~ (depending on context)
^
%
Math.Pow(x, y) (no exponentiation operator)
= or (depending on context)
!=
!=
x ? y : z
x ?? y
x / (double)y
x / y
x / y
Convert.ToInt32(x) / Convert.ToInt32(y)

Optional Parameters

VB.NETC#
Sub Method(p1 As Integer, Optional p2 As Integer = 0) public void Method(int p1, int p2 = 0)

Named Arguments

VB.NETC#
Method(p1 := 2, p2 := 3) Method(p1 : 2, p2 : 3)
VB.NETC#
Sub Method(ParamArray myParam As Object())
End Sub
void Method(params object[] myParam)
{
}

Property

VB.NETC#
Property MyProperty() As Integer
Get
Return field
End Get
Set (ByVal var As Integer)
field = var
End Set
End Property
public int MyProperty
{
get
{
return field;
}
set
{
field = value;
}
}

Indexer

VB.NETC#
Private field() As Integer
Public Default Property Item(ByVal index As Integer) As Integer
Get
Return field(index)
End Get
Set(ByVal value As Integer)
field(index) = value
End Set
End Property
private int[] field
public int this[int index]
{
get
{
return field[index];
}
set
{
field[index] = value;
}
}

Parameterized Property

VB.NETC# (no direct equivalent)
Public Property ParameterizedProperty(ByVal i As Integer) As Integer
Get
Return GetFoo(i)
End Get
Set(value As Integer)
SetFoo(i, value)
End Set
End Property
public int ParameterizedProperty(int i)
{
return GetFoo(i);
}
public void set_ParameterizedProperty(int i, int value)
{
SetFoo(i, value);
}

For simple cases, VB's Select construct can be converted to the C# switch construct. However, if any of the Case statements include range or non-constant expressions, then the equivalent is an if/else block.

VBC#
'converts to switch:
Select Case x
Case 0
...
Case 1
...
End Select
'converts to if/else:
Select Case x
Case 1 To 3
...
Case Is < 10, Is > 20, Is = 15
...
End Select
//converts to switch:
switch (x)
{
case 0:
//...
break;
case 1:
//...
break;
}
//converts to if/else:
if (x >= 1 && x <= 3)
{
...
}
else if ((x < 10) || (x > 20) || (x 15))
{
...
}
VB.NETC#
SyncLock x
...
End SyncLock
lock (x)
{
...
}
VB.NETC#
Public Function TupleReturningMethod1() As (first As String, middle As String, last As String)
'... retrieve first, middle and last
Return (first, middle, last)
End Function
'option to not assign names to tuple fields:
Public Function TupleReturningMethod2() As (String, String, String)
'... retrieve first, middle and last
Return (first, middle, last)
End Function
Public Sub CallTupleMethods()
'assign the tuple to an implicitly-type variable:
Dim names = TupleReturningMethod1()
'can reference different parts of tuple via 'Item1', 'Item2', etc.
Foo(names.Item1, names.Item3)
'can reference different parts via names provided in tuple header:
Foo(names.first, names.last)
'assign the tuple to an explicitly-typed variable:
Dim tuple As (first1 As String, middle1 As String, last1 As String) = TupleReturningMethod1()
End Sub
public (string first, string middle, string last) TupleReturningMethod1()
{
//... retrieve first, middle and last
return (first, middle, last);
}
//option to not assign names to tuple fields:
public (string, string, string) TupleReturningMethod2()
{
//... retrieve first, middle and last
return (first, middle, last);
}
public void CallTupleMethods()
{
//assign the tuple to an implicitly-type variable:
var names = TupleReturningMethod1();
//can reference different parts of tuple via 'Item1', 'Item2', etc.
Foo(names.Item1, names.Item3);
//can reference different parts via names provided in tuple header:
Foo(names.first, names.last);
//assign the tuple to an explicitly-typed variable:
(string first1, string middle1, string last1) tuple = TupleReturningMethod1();
}
VB.NETC#
x = TypeOf y Is z
v = GetType(w)
x = y is z;
v = typeof(w);

VB has two ways of declaring access to an unmanaged dll - the legacy 'Declare' syntax and the modern DllImport syntax (which is also used by C#).

VB.NETC#
'legacy syntax:
Public Declare Function APIFunction Lib 'kernel32'(ByRef x As String) As Integer
'modern syntax:
Imports System.Runtime.InteropServices
<DllImport('kernel32')>
Public Shared Function APIFunction(ByRef x As String) As Integer
End Function
using System.Runtime.InteropServices;
[DllImport('kernel32')]
public static extern int APIFunction(ref string x);

VB 'Collection' is a strange beast in that it allows treating the collection alternately as a keyed list or positional list so a single .NET collection will not capture everything. Also, it's 1-based, unlike nearly all other collections.
The following helper class is used by Instant C# to replicate the behavior of the VB Collection class. Note that it's intended as a drop-in replacement so it uses 1-based parameters. The replacement collection is made generic as an improvement - replace 'Collection' with 'Collection<object>' for the exact VB equivalent, but you should specify the actual type even though you don't do this in VB.

//----------------------------------------------------------------------------------------
// Copyright © 2003 - 2021 Tangible Software Solutions, Inc.
// This class can be used by anyone provided that the copyright notice remains intact.
//
// This class replicates the behavior of the VB Collection class.
//----------------------------------------------------------------------------------------
using System.Collections.Generic;
using System;
public class Collection<T>
{
private List<T> objects = new List<T>();
private List<string> keys = new List<string>();
public void Add(T newObject, string key = null, object before = null, object after = null)
{
if (after != null)
{
if (after as string != null)
Insert(newObject, keys.IndexOf(after as string) + 1, key);
else
Insert(newObject, (int)after, key);
}
else if (before != null)
{
if (before as string != null)
Insert(newObject, keys.IndexOf(before as string), key);
else
Insert(newObject, (int)before - 1, key);
}
else
Insert(newObject, objects.Count, key);
}
private void Insert(T newObject, int index, string key)
{
objects.Insert(index, newObject);
keys.Insert(index, key);
}
public void Clear()
{
objects.Clear();
keys.Clear();
}
public bool Contains(string key)
{
return keys.Contains(key);
}
public int Count
{
get
{
return objects.Count;
}
}
public void Remove(string key)
{
RemoveAt(keys.IndexOf(key));
}
public void Remove(int positionOneBased)
{
RemoveAt(positionOneBased - 1);
}
private void RemoveAt(int index)
{
objects.RemoveAt(index);
keys.RemoveAt(index);
}
public T this[int positionOneBased]
{
get
{
return objects[positionOneBased - 1];
}
}
public T this[string key]
{
get
{
return objects[keys.IndexOf(key)];
}
}
public IEnumerator<T> GetEnumerator()
{
return objects.GetEnumerator();
}
}

Instant C# converts calls to the legacy VB DateDiff function and IsDate function via the following helper class inserted into the conversion output:

//----------------------------------------------------------------------------------------
// Copyright © 2003 - 2021 Tangible Software Solutions, Inc.
// This class can be used by anyone provided that the copyright notice remains intact.
//
// The methods in this class replicate the behavior of IsDate and DateDiff.
//----------------------------------------------------------------------------------------
using System;
using System.Globalization;
public static class DateHelper
{
public static bool IsDate(object expression)
{
if (expression null)
return false;
DateTime testDate;
return DateTime.TryParse(expression.ToString(), out testDate);
}
public enum DateInterval
{
Day,
DayOfYear,
Hour,
Minute,
Month,
Quarter,
Second,
Weekday,
WeekOfYear,
Year
}
public static long DateDiff(DateInterval intervalType, DateTime dateOne, DateTime dateTwo)
{
switch (intervalType)
{
case DateInterval.Day:
case DateInterval.DayOfYear:
TimeSpan spanForDays = dateTwo - dateOne;
return (long)spanForDays.TotalDays;
case DateInterval.Hour:
TimeSpan spanForHours = dateTwo - dateOne;
return (long)spanForHours.TotalHours;
case DateInterval.Minute:
TimeSpan spanForMinutes = dateTwo - dateOne;
return (long)spanForMinutes.TotalMinutes;
case DateInterval.Month:
return ((dateTwo.Year - dateOne.Year) * 12) + (dateTwo.Month - dateOne.Month);
case DateInterval.Quarter:
long dateOneQuarter = (long)Math.Ceiling(dateOne.Month / 3.0);
long dateTwoQuarter = (long)Math.Ceiling(dateTwo.Month / 3.0);
return (4 * (dateTwo.Year - dateOne.Year)) + dateTwoQuarter - dateOneQuarter;
case DateInterval.Second:
TimeSpan spanForSeconds = dateTwo - dateOne;
return (long)spanForSeconds.TotalSeconds;
case DateInterval.Weekday:
TimeSpan spanForWeekdays = dateTwo - dateOne;
return (long)(spanForWeekdays.TotalDays / 7.0);
case DateInterval.WeekOfYear:
DateTime dateOneModified = dateOne;
DateTime dateTwoModified = dateTwo;
while (dateTwoModified.DayOfWeek != DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek)
{
dateTwoModified = dateTwoModified.AddDays(-1);
}
while (dateOneModified.DayOfWeek != DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek)
{
dateOneModified = dateOneModified.AddDays(-1);
}
TimeSpan spanForWeekOfYear = dateTwoModified - dateOneModified;
return (long)(spanForWeekOfYear.TotalDays / 7.0);
case DateInterval.Year:
return dateTwo.Year - dateOne.Year;
default:
return 0;
}
}
}

Only simple cases of VB legacy error handling can be converted to C#.

C to vb.net code converter
VB.NETC#
Public Sub LegacyErrorHandling()
On Error GoTo ErrorHandler
'... main logic
ErrorHandler:
'... error handling code
End Sub
public void LegacyErrorHandling()
{
try
{
//... main logic
}
catch
{
//... error handling code
}
}

Instant C# converts calls to the legacy VB IsNumeric and Val functions via the following helper class inserted into the conversion output:

//----------------------------------------------------------------------------------------
// Copyright © 2003 - 2021 Tangible Software Solutions, Inc.
// This class can be used by anyone provided that the copyright notice remains intact.
//
// The methods in this class replicate the behavior of IsNumeric and Val.
//----------------------------------------------------------------------------------------
using System;
using System.Globalization;
public static class NumericHelper
{
public static bool IsNumeric(object expression)
{
if (expression null)
return false;
double testDouble;
if (expression is string)
{
CultureInfo provider;
if (((string)expression).StartsWith('$'))
provider = new CultureInfo('en-US');
else
provider = CultureInfo.InvariantCulture;
if (double.TryParse((string)expression, NumberStyles.Any, provider, out testDouble))
return true;
}
else
{
if (double.TryParse(expression.ToString(), out testDouble))
return true;
}
//VB's 'IsNumeric' returns true for any boolean value:
bool testBool;
if (bool.TryParse(expression.ToString(), out testBool))
return true;
return false;
}
public static double Val(string expression)
{
if (expression null)
return 0;
//try the entire string, then progressively smaller substrings to replicate the behavior of VB's 'Val', which ignores trailing characters after a recognizable value:
for (int size = expression.Length; size > 0; size--)
{
double testDouble;
if (double.TryParse(expression.Substring(0, size), out testDouble))
return testDouble;
}
//no value is recognized, so return 0:
return 0;
}
public static double Val(object expression)
{
if (expression null)
return 0;
double testDouble;
if (double.TryParse(expression.ToString(), out testDouble))
return testDouble;
//VB's 'Val' function returns -1 for 'true':
bool testBool;
if (bool.TryParse(expression.ToString(), out testBool))
return testBool ? -1 : 0;
//VB's 'Val' function returns the day of the month for dates:
DateTime testDate;
if (DateTime.TryParse(expression.ToString(), out testDate))
return testDate.Day;
//no value is recognized, so return 0:
return 0;
}
public static int Val(char expression)
{
int testInt;
if (int.TryParse(expression.ToString(), out testInt))
return testInt;
else
return 0;
}
}

Instant C# converts calls to the legacy VB Mid statement (unrelated to the Mid function) via the following helper class inserted into the conversion output:

//----------------------------------------------------------------------------------------
// Copyright © 2003 - 2021 Tangible Software Solutions, Inc.
// This class can be used by anyone provided that the copyright notice remains intact.
//
// The methods in this class replicate the behavior of miscellaneous VB features.
//----------------------------------------------------------------------------------------
using System;
public static class ConversionHelper
{
public static void MidStatement(ref string target, int oneBasedStart, char insert)
{
//These 'MidStatement' method overloads replicate the behavior of the VB 'Mid' statement (which is unrelated to the VB 'Mid' function)
if (target null)
return;
target = target.Remove(oneBasedStart - 1, 1).Insert(oneBasedStart - 1, insert.ToString());
}
public static void MidStatement(ref string target, int oneBasedStart, string insert)
{
//These 'MidStatement' method overloads replicate the behavior of the VB 'Mid' statement (which is unrelated to the VB 'Mid' function)
if (target null || insert null)
return;
target = target.PadRight(target.Length + insert.Length).Remove(oneBasedStart - 1, insert.Length).Insert(oneBasedStart - 1, insert).Substring(0, target.Length);
}
public static void MidStatement(ref string target, int oneBasedStart, string insert, int length)
{
//These 'MidStatement' method overloads replicate the behavior of the VB 'Mid' statement (which is unrelated to the VB 'Mid' function)
if (target null || insert null)
return;
int minLength = Math.Min(insert.Length, length);
target = target.PadRight(target.Length + insert.Length).Remove(oneBasedStart - 1, minLength).Insert(oneBasedStart - 1, insert.Substring(0, minLength)).Substring(0, target.Length);
}
//... more helper methods
}

VB.NETC# (omitting null handling)
LCase(x)
UCase(x)
Left(x, 2)
Right(x, 2)
Trim(x)
LTrim(x)
RTrim(x)
Mid(x, 3)
InStr(x, y)
InStrRev(x, y)
x.ToLower()
x.ToUpper()
x.Substring(0, 2)
x.Substring(x.Length - 2)
x.Trim(' ')
x.TrimStart(' ')
x.TrimEnd(' ')
x.Substring(2)
x.IndexOf(y) + 1
x.LastIndexOf(y) + 1
VB.NETC#
Dim myIntegerVar%
Dim myStringVar$
Dim myFloatVar!
Dim myDoubleVar#
int myIntegerVar = 0;
string myStringVar = null;
float myFloatVar = 0;
double myDoubleVar = 0;