UGTS Document #71 - Last Modified: 8/29/2015 3:23 PM
Migrating code from VB.NET to C#

VB.NET and C# are very similar languages, because they both use the same .NET Framework and for the most part the merely use different syntax to express the same things. Even so, it can be daunting to convert a large project from one language to the other in a short amount of time.

SharpDevelop is a useful tool which can greatly speed up this process. You can load a single file or an entire project and convert all the code from VB.NET to C#. There are some limitations however:

  • Web Projects - Visual Web Developer projects aren't supported by SharpDevelop.  You can't load an entire website and convert it at once.
  • Form Designer Code - SharpDevelop will convert all the code in a windows form class, but it will do so in a way that break the ability to load the form in the form designer.
  • Imperfect Translation - SharpDevelop handles some language elements badly, such as the conditional assignment operator, declaring variables as var vs. dynamic, etc...
  • Language Differences - VB.NET and C# are closely related in capabilities, but there are some intentional differences between the two.  C# is designed to be stricter and more exact than VB.  Some things which are easy to do in VB are not so easy to do, or are discouraged, in C#.

Here is a procedure can handle the translation as quickly as possible:

  • Core Class Library Projects - if you have core class library projects which are used by other projects, convert those first.  Visual Studio has no problem having a solution where some projects use VB.NET and others use C# - it will compile each to its own assembly and link them together without problems.  For each project you convert, create a new directory side by side with the old one, named something like [Project][N], where N is the next major revision number of your project.  Convert the entire project in SharpDevelop and save the new project to the new folder.
  • Var / Dynamic - Search / Replace all instances of the word 'dynamic' with 'var' (do this replacement one at a time to make sure that you don't inadvertently replace this in comments or text).   Later you can go back and change the variables which really ought to be dynamic (there are usually only a small fraction in your project).
  • Namespace Importing - Unlike VB.NET, C# files must explicitly declare the list of namespaces that are used / imported in each file, there is no project-wide setting for namespaces to import in each file.  Therefore, it will probably be fastest to create a code file which has the project wide using statements that every file should have, and then copy/paste this into each converted C# file in your project.  This list should include the namespace 'Microsoft.VisualBasic' initiallly to ease the transition.  Later you can re-work your code to remove this.
  • No Global Methods - Unlike VB.NET, if you define a static method or member in a static module, you have to fully reference the name with the module name to access it.  In VB.NET, all you have to do is call the function by name.  This means that you might need to go through the code to fully qualify some method or properties that you are accessing.
  • No DateTime Literals - In VB.NET you can define literal date time values using the #...# syntax.  That doesn't exist in C#.  If you only need a date literal in order to compare two dates, sometimes you can instead get the Year of the date and do an integer comparison instead.  If this isn't enough, you could have a property which returns the date literal value, and this property could get the date value by creating it dynamically from a string.
  • Conditional Assignment Operator - SharpDevelop has a bug / deficiency that it will convert the If() function to the (a ? b : c) conditional assignment operator, but it leaves out the outer parenthesis.  This is difficult to catch because it doesn't always cause a compile time error, but it often changes the way the code works due to operator precedence.  The only way to fix this is to go through every instance where you use conditional assignment and make sure it the converted code is correct.
  • Functions, Properties, and Indexers - VB.NET is lenient / lazy / permissive when it comes to functions and properties, whereas C# is much more rigid.  In C#, properties cannot have arguments.  If you have such a property, in C# you must either convert it into a function / method or an indexer.  Indexers are like default properties in VB.NET, but in C# they must be default, there is no such thing as a secondary indexer with a special name - every indexer on a class must be named 'this' and invoked on the client side like you would call a default property with arguments in VB.NET.  This may force you to refactor some of your code as you convert it to C#.   Also, whereas in VB.NET you can leave out the parenthesis when you call a function / method or constructor with no arguments, this is not allowed in C#.  For each class you're converting, you'll need to think carefully about what should be a property vs. indexer vs. method, and then adapt your client side code to call it that way.

    Also, if you define an indexer, the client side code must invoke the indexer like an array with square brackets [] rather than parenthesis.  SharpDevelop is not able at conversion time to tell the difference between an indexer and a property, and so it converts them all with parenthesis.  After conversion, you'll need to convert parenthesis to [] brackets where needed.
  • VB Functions - If you want to get rid of references to the VB namespace entirely, there are a number of function calls that will need to be converted to more basic funtions in .NET:
    Strings.Format(expression, formatString) should be changed to expression.ToString(formatString).
    DateAndTime.MonthName(intMonth, abbrev) can (usually) be changed to month.ToString(abbrev ? "MMM" : "MMMM").
    DateAndTime.DateDiff(interval, a, b) can be changed (usually) to accessing a property on the TimeSpan returned by (a-b).  For differences in units of years, quarters, or months, you usually need custom code that is tailored to your application.
    Strings.Split(s, delimiter) can be replaced with s.Split(new string[] {delimiter}, StringSplitOptions.None).
  • Event Handlers - Whereas VB has the Handles keyword, C# has no such thing - it is instead expected that the developer will call AddHandler or use the += operator to add event handlers explicitly to events.  Search through the original VB module to find all the places where Handles was used, and add expilicit calls to the C# code to make sure these events get handled in the same way, if the conversion process did not already take care of this for you.  And if this is a web page, make sure that the event handlers are wired up in the Page_Init call, after InitializeComponent is called, and not in the constructor function, because the controls don't get created until after InitializeComponent is called.
  • Foreach Loop Variables - The conversion process will create two separate variables a foreach loop - the iterator, and a second variable which is assigned from it in the loop body.  This is done because in C# the loop variable cannot be modified by the loop code, and having two separate variables prevents this from being a problem.  However it is also very wordy and sometimes wrong.  Search for all the instances of foreach in your code, and change the loop variable to be a single variable declared using 'var' wherever possible for simplicity.
  • Website App_Code - Since a website cannot be converted as an entire project by SharpDevelop, an alternate strategy is recommended here.  If the website has a lot of code in the App_Code directory, create a new empty C# class library specifically for the project and begin moving App_Code modules out of here one at a time into the new class library.  Load the module code into a new file in SharpDevelop, convert that single file to C#, and paste it into a new file in the class library.  Repeat the above steps for this file to fixup all the conversion errors.  Then comment out the module from the website, and adjust all calls to the module to go to the class library instead.
  • Website Pages - these cannot be converted the same way as App_Code modules because there is a tight coupling between the ASPX file and the code-behind file. Controls members are defined by name in the ASPX file, and the compiler recognizes these automatically in the code-behind file.  If you try to move the code-behind file to a separate class library, this link gets broken and the members are no longer defined (except where you explicitly define them).

    One way to deal with this is to create a separate class to hold the logic and have the constructor of this class use the Page to find the controls that it needs and wire itself up to those controls.  This can be a good way to re-use form code between website or even on multiple similar forms on the same website.  However, it is also a fair amount of work, and it is not strictly necessary during conversion.

    A faster alternate approach which can be used for web pages is just to convert the individual files in place to C#.  Unlike app code modules, website projects are fully able to have a mix of VB and C# code behind files in web pages, and the debugger can even step into both kinds of file simultaneously.

    To convert the file, load the content of the code behind file into a new empty VB file in SharpDevelop, convert it to C#, and manually create a new .aspx.cs file in the website directory next to the .aspx.vb file, and paste in the contents.  Then through Windows Explorer rename the .vb file to .vba so that the compiler ignores it.  Open the .aspx file in a text editor and change the top line to show Language="C#" and the updated path for the CodeFile attribute.  Then go to Website, Unload Project, and then right click the project and Reload Project to see the changes. Now proceed to fixup the C# file that has just been converted using the rules followed previously.

After you've fully migrated a project to C# and tested it, you can begin cleanup of VB references as follows:

  • Increment / Decrement - You can search and replace += 1 with ++ and -= 1 with --
  • Remove Unused Usings - For each file in your project, you can trim out unused using directives by right clicking the source file, Organize Usings, Removed Unused Usings.
  • VisualBasic References - Search for the text VisualBasic throughout the project or solution.  Use the above steps to replace these calls with the equivalent core .NET functions.