Document Info
Authored by:
Daniel Stolt, Perceptible
Lars Bergman, Sigma Solutions AB
Revision history: | Author | Version | Date | Change |
| Daniel Stolt | 1 | 2008-03-06 | Initial draft. |
| Daniel Stolt | 2 | 2008-03-07 | Incorporated minor feedback from Magnus Markling. |
| Daniel Stolt | 3 | 2008-03-26 | Removed warning about the Exit Try bug in VB, as it was reportedly fixed in VB 2003. |
| Daniel Stolt | 4 | 2008-11-10 | Added a section on collection initializers in C#. |
| Daniel Stolt | 5 | 2009-09-03 | Publish as a blog page. |
Introduction
This article attempts to provide an objective comparison of key differentiating features of the Microsoft Visual C# and Microsoft Visual Basic programming languages on the Microsoft .NET platform. The comparison is based on C# version 3.0 and VB version 9.0, i.e. the versions shipped with Microsoft Visual Studio 2008 and the Microsoft .NET Framework 3.5.
Aspects covered in this comparison include:
- Language constructs and features.
- Visual Studio IDE features specific to each language, including code editor, designer tools, build process and project model features.
Aspects not covered in this comparison include:
- Features that are equivalent in both languages as of the current versions, such as the “using” keyword or support for XML comments.
- Matters of prior developer knowledge, experience or predisposition, such as whether C# is easier to learn if you already know Java.
- Matters of personal taste, such as whether the syntax of one language is more elegant or readable than the other.
- Bugs.
NOTE: I try to maintain this comparison as extensive and up-to-date as possible. If you are aware of a feature of either language that is missing from this comparison, please let me know (send a message through the contact page) about it and I will add it to the list.
C# Differentiating Features
This section describes features that are present in C# but missing from VB, as well as features that are simply designed and/or implemented differently than their VB equivalents. Features are listed in the order in which they were added to the language, with newer features first.
Lambda Expressions with No Return Value
In VB lambda expressions must always return a value, but in C# you can write lambda expressions that simply perform an operation without returning a value. This makes it possible to write code such as the following:
1: // r.Stop() is declared as public void Stop().
2: myRobots.ForEach(r => r.Stop());
VB NOTE: Statement lambdas will be included in VB10.
Statement Lambda Expressions
C# provides support for statement lambda expressions. A statement lambda resembles an expression lambda except that the statement(s) is enclosed in braces. The body of a statement lambda can consist of any number of statements. This makes it possible to write code such as the following:
1: myStrings.ForEach(n => { string s = n + " " + "World"; Console.WriteLine(s); });
VB NOTE: This is one of the top candidates for addition in VB 10 according to a blog post by Paul Vick.
Auto-Implemented Properties
Auto-implemented properties make property-declaration more concise when no additional logic is required in the property accessors. When you declare a property as shown in the following example, the compiler creates a private, anonymous backing field can only be accessed through the property's get and set accessors.
1: class LightweightCustomer
2: {
3: public double TotalPurchases { get; set; }
4: public string Name { get; private set; } // read-only
5: public int CustomerID { get; private set; } // read-only
6: }
Built-in Refactoring
The C# editor provides a number of refactoring operations out of the box.
VB NOTE: Microsoft makes available for free a Visual Studio add-in from DevExpress that adds a wealth of refactoring support to VB 2008. For more information and download links, see:
http://msdn2.microsoft.com/en-us/vbasic/bb693327.aspx
http://www.devexpress.com/Products/NET/IDETools/VBRefactor/
Organize Usings
Over time, source files may become bloated and difficult to read because of unnecessary and unorganized using directives. The C# editor provides automated operations for removing unused using statements from source files and/or sorting using statements.
Iterators (“yield” Keyword)
An iterator is a method, “get” accessor, or operator that performs a custom iteration over an array or collection class by using the “yield” keyword. The yield return statement causes an element in the source sequence to be returned immediately to the caller before the next element in the source sequence is accessed.
For more information on iterators, see:
http://msdn2.microsoft.com/en-us/library/dscyy5s0.aspx
Anonymous Methods
Creating anonymous methods is essentially a way to pass a code block as a delegate parameter. By using anonymous methods, you reduce the coding overhead in instantiating delegates by eliminating the need to create a separate method. This makes it possible to write code such as the following:
1: Thread t1 = new Thread(delegate()
2: {
3: System.Console.Write("Hello, ");
4: System.Console.WriteLine("World!");
5: });
6: t1.Start();
Ability to Declare Class as Static
The “static” keyword can be applied to a class in C#, which requires that all members of that class be declared as static as well.
Collapse/Expand Code Blocks
Code blocks (portions of code beginning with “{“ and ending with “}”) on all levels, including within procedures, can be collapsed and expanded within the C# editor.
Case Sensitivity
C# is a case sensitive language. Identifiers can be differentiated by case only, although this is not a recommended practice.
CLS Compliance Warnings
When a program element is decorated with the CLSCompliantAttribute, the C# compiler generates warnings for any non-compliant exposed by that program element. The VB compiler produces no such warnings.
VB NOTE: CLSCompliantAttribute documentation states: “The current Microsoft Visual Basic compiler intentionally does not generate a CLS-compliance warning, however, a future release of the compiler will issue that warning.”
[According to documentation at http://msdn2.microsoft.com/en-us/library/bhc3fa7f.aspx these warnings are also created by the VB compiler! Should this feature be removed from this list?]
Unsafe Code and Pointers
To maintain type safety and security, by default C# does not support pointer arithmetic. However, by using the “unsafe” keyword, it is possible to define an unsafe context in which pointers can be used.
For more information on unsafe code and pointers, see:
http://msdn2.microsoft.com/en-us/library/t2yzs44b.aspx
VB NOTE: VB does support using the IntPtr type which works well for calling native APIs in most cases.
Inline Assignments
Multiple assignments can be “chained” together, making it possible to write code such as the following:
1: int a, b, c;
2: a = b = c = 5;
Collection Initializers
Any collection object that implements ICollection<T> can be populated with items inline at initialization (as opposed to manually calling its Add() method in subsequest stamenents) using code such as the following:
1: List<string> names = new List<string> { "Alice", "Bob", "Chris" };
VB NOTE: Collection initializers will be included in VB10.
“volatile” Keyword
The “volatile” keyword indicates that a field might be modified by multiple threads that are executing at the same time. Fields that are declared volatile are not subject to compiler optimizations that assume access by a single thread.
For more information on the “volatile” keyword, see:
http://msdn2.microsoft.com/en-us/library/x13ttww7.aspx
Regions inside Methods
Regions (declared using the “#region” keyword) can be declared within methods, whereas in VB they can only exist outside methods.
Implicit Interface Implementation
In C# you have a choice between implicit and explicit interface implementation. The VB interface implementation is equivalent of C# explicit implementation. Implicit implementation in C# means that class members can be matched to the interface members they implement solely based on sharing the same name, eliminating the need to specify which interface member the class member implements.
Project Default Namespace
The default namespace project setting behaves differently in C# than in VB. In C#, this setting merely specifies the namespace in which newly created types should be declared (in combination with the name of the subfolder in which they are created). Types that are not explicitly declared within a namespace are not part of any namespace, regardless of this project setting.
Preprocessor Directives
The C# compiler supports considerably more preprocessor directives than the VB compiler. The following preprocessor directives are available in C#:
- #if
- #else
- #elif
- #endif
- #define
- #undef
- #warning
- #error
- #line
- #region
- #endregion
- #pragma
- #pragma warning
- #pragma checksum
The VB compiler supports only the following:
- #Const
- #ExternalSource
- #If...Then...#Else
- #Region
VB Differentiating Features
This section describes features that are present in VB but missing from C#, as well as features that are simply designed and/or implemented differently than their C# equivalents. Features are listed in the order in which they were added to the language, with newer features first.
XML Literals
Support for More LINQ Operators
VB supports all the same LINQ operators than C# does, but in addition VB supports the following LINQ operators which C# does not support:
- Aggregate
- Skip
- SkipWhile
- Take
- TakeWhile
In addition, the Select clause is optional in VB. Omitting it means the same things as specifying a Select clause equal to the From clause.
More Advanced IntelliSense
“And” and “Or” Keywords (Boolean Operators)
VB provides two sets of Boolean operators: “AndAlso” and “OrElse” which are short-circuiting, and “And” and “Or” which are non-short-circuiting, whereas C# only provides short-circuiting Boolean operators.
“My” Namespace
The “My” namespace provides access to information and default object instances that are related to the application and its run-time environment. This information is organized in a format that is discoverable through IntelliSense and logically delineated according to use.
For more information, see:
http://msdn2.microsoft.com/en-us/library/5btzf5yk.aspx
“If” and “IIf” Functions
VB provides a choice between three slightly different constructs that perform roughly the same task as the C# “… ? … : …” syntax. The VB “IIf” function is the legacy non-short-circuiting version which means both expressions will always be evaluated. There is also the newer “If” function which, when called with three arguments, is a short-circuiting direct equivalent of the C# construct.
Furthermore, the “If” function can also be called with two arguments as a syntactic shortcut to test for and provide an alternate value for null:
1: ' If a is null then c will be assigned the value of b, otherwise c will be
2: ' assigned the value of a.
3: Dim c = If(a, b)
“Option Strict Off” Keyword
“Option Strict Off” can be used to specify to the VB compiler that explicit narrowing conversions and late binding are allowed. Although using “Option Strict Off” in code which does not require late binding is not a recommended practice, this option can be very useful in some tricky COM interop situations.
Optional Parameters
In VB you can specify that a procedure parameter is optional and no argument has to be supplied for it when the procedure is called. Optional parameters are indicated by the Optional keyword in the procedure definition.
Support for optional parameters is especially useful for interoperating with COM-based code. COM supports optional parameters, and they are used heavily in the Microsoft Office interop assemblies, which makes VB more suitable than C# for COM automation tasks in general, and Office automation in particular.
Note however that exposing optional parameters makes your code non CLS compliant.
ComClassAttribute Support
The ComClassAttribute attribute instructs the VB compiler to add metadata that allows a class to be exposed as a COM object. This makes it simple to expose a .NET class as a COM object.
“WithEvents” keyword
The “WithEvents” keyword is used to expose events from a member variable. It enables handlers for events raised by the object referenced by the member variable to be wired up declaratively using the “Handles” keyword.
The event registration is specified with the event handler method declaration – there is no need to register it imperatively somewhere else. Event handlers are automatically rewired if the member variable is changed to reference a different object.
This enables events to be handled using code such as the following:
1: Private WithEvents m_AddButton As Button
2: Private Sub ClickHandler(sender As Object, e As EventArgs) Handles m_AddButton.Click
3: End Sub
Case Insensitivity
VB is a case insensitive language. Identifiers cannot be differentiated by case only. The VB compiler treats identifiers which differ only by case as the same.
Automatic Case Correction
The VB code editor provides automatic correction of case. This applies to all elements of the source code. For example, if you declare a variable as “myValue” and subsequently refer to it as “Myvalue” in an expression, the editor changes the expression to “myValue” as soon as you move the caret away from that line of code.
Dynamic Arrays
VB provides native support for directly declaring and using dynamic arrays. One example of this support is the “ReDim Preserve” statement, which resizes an array while preserving its existing contents.
“With” Keyword
The “With” keyword allows you to perform a series of statements on a specified object without requalifying the name of the object. If the qualification path to the object is long, using “With” can improve your performance. A “With” block also reduces repetitive typing of the qualification path and the risk of mistyping one of its elements.
Parameterized Properties/Named Indexers
VB supports creating and using properties that take one or more parameters.
[Add sample code]
This ability also makes it possible to create named indexers, since any property with any name can be fitted with an index parameter.
Pretty Listing (Reformatting) Of Code
This option causes the VB editor to reformat your code as appropriate when the caret leaves an edited line of code. More specifically, the code editor will:
- Align your code to the correct tab position
- Normalize white space
- Recase keywords, variables, and objects to the correct case
- Add a missing “Then” to an “If...Then” statement
- Add parentheses to function calls
- Add missing end quotes to strings
- Reformat exponential notation
- Reformat dates
Background Compilation
The VB project and build system in Visual Studio ensures that the Task List, in-line errors and warning, and IntelliSense are always up to date by continuously compiling all code in the background. In contrast, the C# project system performs only limited lexical parsing in the background, which does not identify all errors.
Project Default Namespace
The default namespace project setting behaves differently in VB than in C#. In VB all types not explicitly declared in a namespace will belong to the default namespace. This removes the need for explicitly declaring a namespace in all source files (which you must do in C#) which in turn enables easier reorganization of files within and between projects. In addition, types added to subfolders are not automatically made part of a subfolder-based namespace.
“Imports” Statement on Type Names
VB allows you to specify a full type name in the “Imports” statement. This brings the specified type directly in scope, and allows you to use its members directly without qualifying them with the type name. For example, this can be used to achieve the illusion of a “global” method by declaring the method as “Shared” and importing the class name.
“Module” Keyword
A module in the VB sense of the word is a reference type available throughout its namespace. A module (sometimes called a standard module) is similar to a class but with some important distinctions. Every module has exactly one instance and does not need to be created or assigned to a variable. Modules do not support inheritance or implement interfaces. Notice that a module is not a type in the sense that a class or structure is — you cannot declare a programming element to have the data type of a module.
For more information, see:
http://msdn2.microsoft.com/en-us/library/aaxss7da.aspx
Modules provide a mechanism for creating namespace-scoped methods and variables, which is not possible in #C. Because such members can be used without a type name qualification, you can use them to "extend" the VB language with extra functions. They can also be used to "replace" the standard VB functions with custom implementations, e.g. an MsgBox replacement that automatically logs message box dialogs to a trace listener.
Keywords as Identifiers
In VB it is possible to use language keywords as identifiers by enclosing them in square brackets. The compiled identifier names will be without the square brackets.
“Static” Keyword
Normally, a local variable in a procedure ceases to exist as soon as the procedure stops. A “Static” variable continues to exist and retains its most recent value. The next time your code calls the procedure, the variable is not reinitialized, and it still holds the latest value that you assigned to it. A “Static” variable continues to exist for the lifetime of the class or module that it is defined in.
“Exit Try” Keyword
The “Exit Try” statement is used to unconditionally exit a “Try” or “Catch” block without the need for throwing an exception, while still retaining the guarantee that the “Finally” block will be executed.
“Catch When” Keyword
The optional “When” clause following the “Catch” keyword makes it possible to specify additional conditions that must be true for the Catch to take effect. This enables advanced error handling constructs that are not as easily implemented in C#, such as in the following example:
1: Try
2: ' Perform data access operation here.
3: Catch ex As SqlException When ex.ErrorCode = 1024
4: End Try
“Select Case”
“Select Case” provides much more flexibility than the C# “switch” construct in terms of expressions allowed following the “Case” keyword. C# “switch” allows only literals, while “Select Case” allows for things such as the following:
1: Case Is > 2
2: Case Is < b
3: Case b
4: Case 1 To 99
5: Case Is < MyFunction(a)
Interface Implementation
The VB interface implementation model allows for greater flexibility than the C# counterpart. For example, a single procedure can easily implement multiple interfaces, even if none of them have the same name. Furthermore, procedure name and interface name may differ, such as in the following example:
1: Public Sub MyMethod() Implements IRobot.Stop, IMoveableObject.Stop
2: End Sub
Macro Programming
VB is used as the language for macro programming in the Visual Studio IDE. Macros are a simple yet powerful method of IDE automation.
“MyClass” Keyword
The “MyClass” keyword behaves like an object variable referring to the current instance of a class as originally implemented. “MyClass” is similar to “Me”, but every method and property call on “MyClass” is treated as if the method or property were “NotOverridable”. Therefore, the method or property is not affected by overriding in a derived class. C# provides no mechanism to refer to current class instance members regardless of overrides.
More Statement Completion
The VB code editor generally provides more assistance in statement completion than its C# counterpart. For example, when you type “If a > 2” and pressing Enter, the VB editor adds “Then” to the current line, adds an “End If” on a separate new line, and positions the caret on an empty line in between, so that you can continue typing inside the “If” block. The C# editor provides no such statement completion.
Legacy Functions
VB supports a vast array of legacy functions that have been re-implemented to integrate seamlessly with the world of managed code. These functions can make it easy to perform certain tasks that are cumbersome in C#. One example is the “IsNothing” function, which provides more flexibility than the “Is Nothing” operator. The “DateDiff” function is another example of a legacy VB function that still often proves very useful.
C# Note: Many of the legacy functions in VB are implemented in standard types in the Microsoft.VisualBasic namespace which are consumable from C# as well.
“Or Error” Exception Handling
To this day, VB still retains support for exception handling by means of the legacy “Or Error” construct, which enables some constructs which are not easily implemented in C#. One such construct is “On Error Resume Next” which is equivalent to encapsulating each individual following statement in a separate “Try” block with an empty “Catch” block.