April 2010

Volume 25 Number 04

Visual Basic 2010 - What's New in Visual Basic 2010

By Jonathan Aneja | April 2010

From its inception in 1991, the Visual Basic language has always been a phenomenal productivity tool for building applications. Almost 20 years later, it continues to provide easy access to the Microsoft .NET Framework, allowing developers to write applications that span desktops, phones, browsers and even the cloud.

Microsoft this month will ship Visual Studio 2010, which incorporates version 10 of Visual Basic (sometimes referred to as VB 2010 or VB10). This release, the most powerful yet, contains numerous time-saving features that help developers get more done with fewer lines of code. Here’s everything you need to know to hit the ground running with Visual Basic in Visual Studio 2010.

Coevolution

In the past, Visual Basic and C# were developed by separate teams, which often resulted in features appearing in one language before the other. For example, C# had auto-implemented properties and collection initializers, which weren’t in Visual Basic, and Visual Basic had features such as late binding and optional parameters that weren’t in C#. But whenever a feature appeared in one of the languages, many customers would ask to have the capability added to the other as well.

To address this feedback, Microsoft merged the Visual Basic and C# teams, embracing a strategy of coevolution. The intent is to make the languages advance together. When major functionality is introduced in one language, it should appear in the other as well. This doesn’t mean that every feature will be in both languages and work exactly the same way; indeed, each language has its own history, spirit and feel—traits that are important to maintain. Coevolution does mean that any task you can do in one language should be as simple in the other.

In the .NET Framework 4, both Visual Basic and C# have taken giant strides toward this goal, each adding a number of capabilities the other already had. Coevolution isn’t just about the past, though; it’s also the strategy for future innovation in the languages. In that spirit, the .NET Framework 4 introduces powerful new features, such as the Dynamic Language Runtime, Embed Interop Types and generic variance, in both languages simultaneously, allowing Visual Basic and C# developers to take full advantage of the .NET Framework.

New Features in Visual Basic 2010

The new features in Visual Basic 2010 are designed to help you get more done in fewer lines of code. We (the Visual Basic design team) looked at places where developers often have to write a lot of tedious boilerplate code and investigated ways to get the compiler to do the work instead. That’s the big picture; now let’s delve into some features one by one.

Implicit Line Continuation

Visual Basic is a line-oriented language that uses clear, English-like syntax to enhance readability. But that often results in code that runs up against the 80-character-per-line limit, forcing developers to scroll a lot. You can use the underscore character to tell the compiler that it should keep processing the next line as part of the current one (that is, treat multiple physical lines as a single, logical line). But having to type underscores repeatedly has always been annoying, and in fact, for years the No. 1 feature request has been for the compiler to “just figure it out.”

Well, in Visual Basic 2010, the compiler can. It now knows which tokens (such as commas, parentheses and operators) tend to occur right before the line-continuation character, and it inserts the character so developers no longer need to. For example, ending a Visual Basic statement with a comma is never legal; the compiler knows this, so when it sees a token stream that looks like {comma, enter}, it infers the presence of the line continuation character, as the example in Figure 1 shows.

Figure 1 Inferring Line Continuation

<Extension()>
Function FilterByCountry(
  ByVal customers As IEnumerable(Of Customer),
  ByVal country As String) As IEnumerable(Of Customer)
    Dim query =
      From c In customers
      Where c.Country = country
      Select <Customer>
        <%=
          c.Name &
          "," &
          c.Country
        %>
      </Customer>
    Return query
  End Function

In Visual Basic 2008, the code in Figure 1 would have needed nine underscores. In each of these cases, though, the compiler inferred when the underscore was necessary and allowed it to be omitted:

  • After the <Extension()> attribute
  • After the ( (open paren) in the method declaration
  • After the , (comma) for the first parameter
  • Before the ) (close paren) in the method declaration
  • After the = (equal sign)
  • After the <%= (opening tag for an embedded expression)
  • After each & (ampersand) in the XML literal
  • Before the %> (closing tag for an embedded expression)

This new compiler capability is especially handy for the method signature, which would go well beyond 80 characters in the example shown if each part were on the same line. In Figure 2 you’ll see all the combinations of tokens and placements in which the line-continuation character is implicit.

Figure 2 Where Continuation Characters Are Implicit

Token Before After
, (comma),   .  (dot),   >  (attributes),   (  {  (open brackets),   <%=  (begin embedded expression (XML literals))   X
),   },   ,   ]  (close brackets), %> (close embedded expression) X  

All LINQ keywords:

Aggregate, Distinct, From, Group By, Group Join, Join, Let, Order By, Select, Skip, Skip While, Take, Take While, Where, In, Into, On, Ascending, Descending

X X

Operators:

+ ,   - ,   * ,   / ,   \ ,   ^ ,   >> ,   << ,   Mod,   & ,   += ,   -= ,   *= ,   /= ,   \= ,   ^= ,   >>= ,   <<= ,   &= ,   < ,   <= ,   > ,   >= ,   <> ,   Is,  IsNot,  Like,  And,   Or,  Xor,  AndAlso,  OrElse

  X
With (in an object initializer)   X

As you can see, there are more than 60 places where the language doesn’t require underscores. (In fact, none of the code samples in this article required the line-continuation character.) Of course, you can still use the underscore, so code from previous versions of Visual Basic will still compile as expected.

Statement Lambdas

The term lambda can sound intimidating at first, but a lambda is simply a function defined inside another function. Visual Basic 2008 introduced lambda expressions with the Function keyword:

Dim customers As Customer() = ...
 Array.FindAll(customers, Function(c) c.Country = "Canada")

Lambda expressions give you a nice compact way of expressing logic locally without having to split it across multiple methods. For example, here’s how the previous code would have looked in Visual Basic 2005 (which didn’t support lambda expressions):

Dim query = Array.FindAll(customers, AddressOf Filter)



    ...



Function Filter(ByVal c As customer) As Boolean

  Return c.Country = "Canada"

End Function

Unfortunately, Visual Basic 2008’s lambda expressions required that the expressions return a value, so this:

Array.ForEach(customers, Function(c) Console.WriteLine(c.Country))

would have caused this:

'Compile error: "Expression does not produce a value."

Console.WriteLine is a Sub procedure (void, in C#), so it doesn’t return a value, which is why the compiler gives an error. To deal with this, Visual Basic 2010 introduces support for statement lambdas, which are lambdas that can contain one or more statements:

Array.ForEach(customers, Sub(c) Console.WriteLine(c.Country))

Because Console.WriteLine doesn’t return a value, we can just create a Sub lambda rather than a Function lambda. Here’s another example that uses multiple statements:

Array.ForEach(customers, Sub(c)
                           Console.WriteLine("Country Name:")
                           Console.WriteLine(c.Country)
                         End Sub)

When this code runs, it’ll print two lines for each customer. Also notice that if you hover over cwhen you’re coding, you’ll see that the compiler has inferred the type as Customer (it’s also legal to type c As Customer to state the type explicitly). Dynamically wiring up event handlers is another great use for statement lambdas:

AddHandler b.Click, Sub(sender As Object, e As EventArgs)
                      MsgBox("Button Clicked")
                      'insert more complex logic here
                    End Sub

And, in fact, you can combine statement lambdas with a feature introduced in Visual Basic 2008: relaxed delegates. (You can use delegates—type-safe pointers to functions—to execute multiple functions at once.) This combination produces an even simpler signature:

AddHandler b.Click, Sub()
                      MsgBox("Button Clicked")
                     'insert more complex logic here
                    End Sub

Delegate relaxation lets you completely omit the parameters from an event handler—a nice benefit, given that frequently they’re not used at all, so they just add visual noise.

In addition to the single-line Sub lambdas and multi-line Sub lambdas we’ve seen so far, Visual Basic 2010 also supports multi-line Function lambdas:

Dim query = customers.Where(Function(c)
                              'Return only customers that have not been saved
                              'insert more complex logic here
                              Return c.ID = -1
                            End Function)

Another interesting aspect of statement lambdas is the way they intersect with the anonymous delegates Visual Basic 2008 introduced. People often confuse these with C#’s anonymous methods, though technically they’re not the same. Anonymous delegates occur when the Visual Basic compiler infers a delegate type based on the method signature of a lambda:

Dim method = Function(product As String)
               If product = "Paper" Then
                 Return 4.5 'units in stock
               Else
                 Return 10 '10 of everything else
               End If
             End Function
MsgBox(method("Paper"))

If you run this code, you’ll see the value 4.5 displayed in the message box. Also, if you hover over method, you’ll see the text Dim method As <Function(String) As Double>. Because we provided no actual delegate type, the compiler will generate one automatically, like this:

Delegate Function $compilerGeneratedName$(product As String) As Double

This is called an anonymous delegate, because it appears only in the compiler-produced code, not in the written code. Notice that the compiler inferred the return type as Double, when in fact there was no As clause given to specify the lambda’s return type. The compiler looks at all the return statements inside the lambda and sees the types Double (4.5) and Integer (10):

'Notice the "As Single"
Dim method = Function(product As String) As Single
               If product = "Paper" Then
                 Return 4.5 'units in stock
               Else
                 Return 10 '10 of everything else
               End If
             End Function

It then runs its dominant-type algorithm and determines that it can safely convert 10 to Double but can’t safely convert 4.5 to Integer; thus Double is the better pick.

You also can take control of the return type explicitly, in which case the compiler won’t attempt to infer the type. Rather than relying on the compiler to infer the delegate type, it’s very common to assign a lambda to a variable that has an explicit delegate type:

Dim method As Func(Of String, Single) =
  Function(product)
    If product = "Paper" Then
      Return 4.5 'units in stock
    Else
      Return 10 '10 of everything else
    End If
  End Function

Because an explicit target type was provided, there’s no need to say As String orAs Single; the compiler can infer their presence based on the delegate type from the left-hand side of the statement. 
Thus, if you hover over product you’ll find that the inferred type is String. Specifying As Single is no longer necessary, because the delegate type already provides that information. In the previous example, the signature of the Func delegate (which the .NET Framework includes) looks like this:

Delegate Function Func(Of T, R)(ByVal param As T) As R

with one minor exception, as we’ll see later in the Generic Variance section.

Auto-Implemented Properties

In Visual Basic, properties are class members you use to expose an object’s state to the outside world. A typical property declaration looks something like this:

Private _Country As String
Property Country As String
  Get
    Return _Country
  End Get
  Set(ByVal value As String)
    _Country = value
  End Set
End Property

That’s 10 lines of code for what’s actually a very simple concept.  Given that typical objects often have dozens of properties, you end up including a lot of boilerplate code in class definitions. To make such tasks easier, Visual Basic 2010 introduces auto-implemented properties, which allow you to define a simple property using only one line of code:

Property Country As String

In this case, the compiler will go ahead and generate the Getter, Setter and backing fields automatically. The name of the backing field will always be an underscore followed by the name of the property: _Countryin this case. This naming convention ensures binary serialization compatibility should an auto-implemented property be changed to a regular one. As long as the name of the backing field is the same, binary serialization will continue to work.

One of the cool things you can do with auto-implemented properties is specify initializers that set the property’s default value when the constructor runs. A common scenario with entity classes, for example, sets the primary key to something like -1 to indicate that it’s in an unsaved state. Here’s what that code would look like:

Property ID As Integer = -1

When the constructor runs, the backing field (_ID) will be set to the value -1 automatically. The initializer syntax also works for reference types:

Property OrderList As List(Of Order) = New List(Of Order)

The previous line of code may not feel very “Visual Basic-ish,” given that entering the name of the type twice is redundant. The good news is there’s an even shorter syntax that’s consistent with what Visual Basic allows in regular variable declarations:

Property OrderList As New List(Of Order)

You can even combine this with Object Initializers to allow setting additional properties:

Property OrderList As New List(Of Order) With {.Capacity = 100}

Obviously, for more complex properties, the expanded syntax is still necessary.  You can still type Property{Tab} to activate the old property snippet. Alternatively, after typing the first line of the property, you can just enter Get{Enter}, and the IDE will generate the old-style property:

Property Name As String
  Get
  End Get
  Set(ByVal value As String)
  End Set
End Property

People often remark that the new property syntax is almost identical to the syntax for a public field, so why not use a public field instead? Well, for a few reasons:

  • Much of the .NET data-binding infrastructure works against properties but not fields.
  • An interface can’t enforce the existence of a field; it can enforce that of a property.
  • Properties provide more long-term flexibility for changing business rules. For example, suppose someone introduces the rule that a phone number must be 10 digits. There’s no way to perform this validation when assigning to a public field. Changing a public field to a property is a breaking change for scenarios such as binary serialization and reflection.

Collection Initializers

A common .NET practice is to instantiate a collection and then populate it by calling the Add method once for each element:

Dim digits As New List(Of Integer)
digits.Add(0)
digits.Add(1)
digits.Add(2)
digits.Add(3)
digits.Add(4)
digits.Add(5)
digits.Add(6)
digits.Add(7)
digits.Add(8)
digits.Add(9)

But the result is a lot of syntactic overhead for what’s fundamentally a very simple concept. Visual Basic 2010 introduces collection initializers to let you more easily instantiate collections. With this code:

Dim digits = New List(Of Integer) From {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}

the compiler will generate all the calls to the Add method automatically. You can also use the feature with Visual Basic’s As New syntax:

Dim digits As New List(Of Integer) From {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}

Note that on the Visual Basic Team, we always recommend using the second syntax (As New) over the former, because it makes code resilient against changes to the Option Infer setting.

You can use collection initializers against any type that meets the following requirements:

  • You can iterate over it using a For Each statement—that is, it implements IEnumerable. (For a more precise/detailed definition of a collection type, see section 10.9.3 of the Visual Basic Language 
Specification at msdn.microsoft.com/library/aa711986(VS.71).aspx).
  • It has an accessible (not necessarily public) parameter-less constructor.
  • lt has an accessible (not necessarily public) instance or extension method named Add.

That means you can also use collection initializers with more complex types, such as dictionaries:

Dim lookupTable As New Dictionary(Of Integer, String) From
  {{1, "One"},
   {2, "Two"},
   {3, "Three"},
   {4, "Four"}}

(Note that even though this statement spans five lines, there are no underscores.) In this case, the compiler will generate code that’s equivalent to the old way of initializing the dictionary:

Dim lookupTable As New Dictionary(Of Integer, String)
lookupTable.Add(1, "One")
lookupTable.Add(2, "Two")
lookupTable.Add(3, "Three")
lookupTable.Add(4, "Four")

The compiler is calling an Add method that has twoparameters instead of one. It knows to do this because the values passed into the collection initializer were in nested braces, like this: {{1, “One”}, {2, “Two”}, …}. For each set of nested braces, the compiler attempts to pass those parameters to a compatible Add method.

You can also provide your own custom Add implementation by using an extension method:

<Extension()>
  Sub Add(ByVal source As IList(Of Customer),
          ByVal id As Integer,
          ByVal name As String,
          ByVal city As String)
      source.Add(New Customer With
                 {
                    .ID = id,
                    .Name = name,
                    .City = city
                 })
  End Sub

(Look at all those missing underscores!) This method extends any type that implements IList(Of Customer) and then allows you to use the new collection initializer syntax like this:

Dim list = New List(Of Customer) From
            {
              {1, "Jon", "Redmond"},
              {2, "Bob", "Seattle"},
              {3, "Sally", "Toronto"}
            }

(adding three customers to list). You can also use collection initializers in conjunction with auto-implemented properties:

Property States As New List(Of String) From {"AL", "AK", "AR", "AZ", ...}

Array Literals

In addition to more powerful ways of working with collection types, Visual Basic 2010 also provides some great enhancements for working with arrays. Consider the following code (which works fine in older versions):

Dim numbers As Integer() = New Integer() {1, 2, 3, 4, 5}

It’s obvious from looking at the elements in the array that each is an Integer, so having to actually type out Integer twice in this line doesn’t really add any value. Array literals allow creation of an array by putting all of its elements inside braces, and then having the compiler infer the type automatically:

Dim numbers = {1, 2, 3, 4, 5}

The type of numbers isn’t Object, but rather Integer() (as long as Option Infer is on), because the array literal can now stand by itself and has its own type. Consider a more complicated example:

Dim numbers = {1, 2, 3, 4, 5.555}

In this case, the type of numbers will be inferred as Double(). The compiler determines the type by examining each element in the array and calculating the dominant type (using the same algorithm discussed earlier for inferring the return type of a statement lambda). What happens if there’s no dominant  type, such as in the following code:

Dim numbers = {1, 2, 3, 4, "5"}

In this case, converting an Integer to a String would be a narrowing conversion (that is, there would be potential for data loss at runtime), and likewise, converting a String to an Integer would also be a narrowing conversion. The only safe type to pick is Object() (and the compiler will give an error when Option Strict is on).

Array literals can be nested to form either multi-dimensional arrays or jagged arrays:

'2-dimensional array
Dim matrix = {{1, 0}, {0, 1}} 
'jagged array - the parentheses force evaluation of the inner array first
Dim jagged = { ({1, 0}), ({0, 1}) }

Dynamic Language Runtime

While technically a static language at heart, Visual Basic has always had extremely powerful dynamic capabilities, such as late binding. Visual Studio 2010 ships with a new platform called the Dynamic Language Runtime (DLR), which makes it easier to build—and communicate among—dynamic languages. Visual Basic 2010 has been updated to fully support the DLR in its latebinder, letting developers use libraries and frameworks developed in other languages such as IronPython/IronRuby.

The cool thing about this feature is that nothing’s changed syntactically (in fact, not a single line of code was modified in the compiler to support this feature). Developers can still make operations late-bound the same way they did in previous versions of Visual Basic. What has changed is code in the Visual Basic Runtime (Microsoft.VisualBasic.dll), which now recognizes the IDynamicMetaObjectProvider interface that the DLR provides. If an object implements this interface, the Visual Basic Runtime will construct a DLR CallSite and allow the object and its providing language to inject their own semantics into the operation.

For example, the Python Standard Libraries contain a file called random.py with a method called shuffle that can be used to randomly rearrange the elements in an array. Calling it is simple:

Dim python As ScriptRuntime = Python.CreateRuntime()
Dim random As Object = python.UseFile("random.py")
Dim items = {1, 2, 3, 4, 5, 6, 7}
random.shuffle(items)

At runtime, Visual Basic sees that the object implements IDynamicMetaObjectProvider and thus passes control to the DLR, which then communicates with Python and executes the method (passing along the array that was defined in Visual Basic as an argument to the method).

That’s an example of invoking a DLR-enabled API, but it’s also possible for developers to create their own APIs that use this feature. The key is to implement the IDynamicMetaObjectProvider interface, in which case the Visual Basic and C# compilers will recognize that the object has special dynamic semantics. Rather than implementing the interface manually, it’s easier to inherit from the System.Dynamic.DynamicObject class (which already implements this interface) and just override a couple of methods. Figure 3 shows a full example of creating a custom dynamic object (a “property bag” that appears to create properties on the fly) and calling it using normal Visual Basic late binding. (For more information on working with DynamicObject, check out Doug Rothaus’ excellent article at blogs.msdn.com/vbteam/archive/2010/01/20/fun-with-dynamic-objects-doug-rothaus.aspx.)

Figure 3 Creating a Custom Dynamic Object and Calling It with Visual Basic Late Binding

Imports System.Dynamic
  Module Module1
    Sub Main()
      Dim p As Object = New PropertyBag
        p.One = 1
        p.Two = 2
        p.Three = 3
      Console.WriteLine(p.One)
      Console.WriteLine(p.Two)
      Console.WriteLine(p.Three)
    End Sub
      Class PropertyBag : Inherits DynamicObject
        Private values As New Dictionary(Of String, Integer)
        Public Overrides Function TrySetMember(
          ByVal binder As SetMemberBinder,
          ByVal value As Object) As Boolean
            values(binder.Name) = value
          Return True
        End Function
        Public Overrides Function TryGetMember(
          ByVal binder As GetMemberBinder,
          ByRef result As Object) As Boolean
          Return values.TryGetValue(binder.Name, result)
        End Function
      End Class
  End Module

Generic Variance

This is a feature that can sound really complicated (with terms like covariance and contravariance) at first, but it’s actually pretty simple. If you have an object of type IEnumerable(Of Apple) and want to assign it to an IEnumerable(Of Fruit), that should be legal, because every Apple is a Fruit (enforced by an inheritance relationship). Unfortunately, before Visual Basic 2010, generic variance was not supported in the compiler, even though it actually was supported in the Common Language Runtime (CLR).

Let’s consider the example in Figure 4. In Visual Basic 2008, the code in Figure 4 would generate a compile error (or if Option Strict is off, a runtime exception) on the Dim enabledOnly line. The workaround was to call the .Cast extension method, as shown here:

'Old way, the call to Cast(Of Control) is no longer necessary in VB 2010
    Dim enabledOnly = FilterEnabledOnly(buttons.Cast(Of Control))

This is no longer necessary, because in Visual Basic 2010, the IEnumerable interface has been marked as covariant by using the Out modifier:

Interface IEnumerable(Of Out T)
  ...
End Interface

Figure 4 An Example of Generic Variance

Option Strict On
Public Class Form1
  Sub Form1_Load() Handles MyBase.Load
    Dim buttons As New List(Of Button) From
      {
        New Button With
        {
          .Name = "btnOk",
          .Enabled = True
        },
        New Button With
        {
          .Name = "btnCancel",
          .Enabled = False
        }
      }
    Dim enabledOnly = FilterEnabledOnly(buttons)
  End Sub
  Function FilterEnabledOnly(
    ByVal controls As IEnumerable(Of Control)
    ) As IEnumerable(Of Control)
    Return From c In controls
    Where c.Enabled = True
  End Function
End Class

This means the generic parameter T is now variant (that is, it works for inheritance relationships) and the compiler will ensure it’s only used in positions where the type is coming out of the interface. Generic parameters can also be contravariant, which means they’re only used in input positions. A type can actually have both. For example, the Func delegate discussed earlier has both contravariant parameters (things that get passed in) and a covariant parameter (for the return type):

Delegate Function Func(Of In T, Out R)(ByVal param As T) As R

You can use the In and Out modifiers on your custom interfaces and delegates. Many commonly used interfaces and delegates in the .NET Framework 4 have already been marked as variant; common examples include all the Action/Func delegates, IEnumerable(Of T), IComparer(Of T) and IQueryable(Of T), among others.

The cool thing about generic variance is that it’s a feature you don’t really need to worry about—if it’s doing its job, you’ll never notice it. Situations that used to cause compile errors or require a call to .Cast(Of T) should work just fine in Visual Basic 2010.

Improved Optional Parameters

Optional parameters provide a handy productivity feature that lets developers make more flexible methods and avoid polluting a class with numerous overloads of a method. One limitation in the past was that optional parameters could not be nullable (or indeed any non-intrinsic structure type). Visual Basic 2010 now lets you define optional parameters of any value type:

Sub DisplayOrder(ByVal customer As Customer,
                 ByVal orderID As Integer,
                 Optional ByVal units As Integer? = 0,
                 Optional ByVal backgroundColor As Color = Nothing)
End Sub

In this case, units is of type Nullable(Of Integer) and backgroundColor is a non-intrinsic structure type, but they can still be used as optional parameters. Visual Basic 2010 also provides better support for optional parameters that are generic.

Embed Interop Types

For applications that perform COM Interop, a common pain point is having to work with Primary Interop Assemblies (PIAs). A PIA is a .NET assembly that serves as a Runtime Callable Wrapper (RCW) over a COM component and has a unique GUID to identify it. .NET assemblies communicate with a PIA, which then performs any necessary marshalling to move data between COM and .NET.

Unfortunately, PIAs can complicate deployment because they’re additional DLLs that need to be deployed to the end users’ machines. They also cause problems for versioning—for example, if you want an application to be able to work against both Excel 2003 and Excel 2007, you’d need to deploy both PIAs with the application.

The Embed Interop Types feature embeds directly into the application, but only the types and members from the PIA that are absolutely necessary, thus removing the need for PIAs to be deployed to the end users’ machines.

To turn on this feature for an existing project (it’s already on by default for new references), select the reference in Solution Explorer and change the Embed Interop Types option in the properties window (see Figure 5). Or, if compiling using the command-line compiler, use the /l (or /link) switch instead of the /r and /reference.

image: Enabling the Embed Interop Types Feature in Solution Explorer

Figure 5 Enabling the Embed Interop Types Feature in Solution Explorer

Once you’ve turned this feature on, the application no longer has a dependency on the PIA. In fact, if you open the assembly in Reflector or ildasm, you’ll notice that there actually isn’t any reference to the PIA at all.

Multi-Targeting

The coolest thing about all the features in Visual Basic 2010 is that you can even use them in projects that target the .NET Framework 2.0 through the .NET Framework 3.5. This means that implicit line continuation, array literals, collection initializers, statement lambdas, auto-implemented properties and so on will all work in existing projects without having to retarget to the .NET Framework 4.

The one exception is Embed Interop Types, which has a dependency on types that are only in the .NET Framework 4; as a result you can’t use it when targeting .NET Framework versions 2.0 through 3.5. Also, the types that are marked as variant are only marked that way in the .NET Framework 4, so in the earlier example, you’d still have to call .Cast(Of T) when targeting versions 2.0 through 3.5. You can, however, make your own variant types (using the In/Out modifiers) when targeting those earlier versions.

To change the current target framework for an application, double-click My Project, click the Compile tab, click Advanced Compile Options and then select from the combo box at the bottom.

When compiling from the command line, there’s actually no command-line switch to enable this feature. Instead, the compiler looks at which assembly provided the definition of System.Object (typically mscorlib) and which framework that assembly is targeting, then stamps that value in your output assembly. (This is the same mechanism the compiler uses when building Silverlight assemblies.) When using the IDE, all this happens transparently, so in general it’s not something you need to worry about.

Try It Out

As you can see, Visual Basic 2010 has many powerful features that let you be more productive while writing fewer lines of code, offloading more work to the compiler. In this article, I’ve only looked at language features, but the Visual Basic 2010 IDE also has a ton of great enhancements. Here’s a partial list:

  • Navigate To
  • Highlight References
  • Generate From Usage
  • Better IntelliSense (substring matching, camel-case lookup, suggestion mode—useful for “test first” styles of development)
  • Multi-Monitor Support
  • Zooming

The Visual Basic team would love to hear your feedback on what we can do to make Visual Basic even better, so send us your comments and questions on Microsoft Connect. To learn more about the language and IDE features, check out the content on msdn.com/vbasic, including the articles, samples and How-Do-I videos. Of course, the best way to learn is by diving in and using the product, so it’s time to install it and try it out.

Want more Visual Basic? You got it. MSDN Magazine *is resuming monthly publication of the Basic Instincts column, which focuses on the Visual Basic developer and related topics and is written by the Visual Basic team at Microsoft.        *


Jonathan Aneja is a program manager on the Entity Framework team at Microsoft. Previously he was the program manager for the Visual Basic compiler during the releases of Visual Basic 2008 and Visual Basic 2010. He has been at Microsoft for four years.

Thanks to the following technical experts for reviewing this article: Dustin Campbell, Jason Malinowski and Lucian Wischik