Alright, so I've spent a lot of my time this summer (and more this fall) going to various groups and talking about the features in C# 3.0.  This is something of a thorn in the side of my good friend Cory Smith, who despite the fact that he is a "Visual Developer" MVP, is the staunchest Visual Basic advocate that I'm aware of.  I swear this man dreams VB, I know he blogs VB over at AddressOf.com.  As such, I thought it was time to give all of my friends who prefer Visual Basic their fair time, or at least some time, so this post details the new features and shows the syntax for things.  There is not exact parity to the C# feature list, but its a close thing, so here we go.

Automatic Properties

We'll start of with the biggest exclusion.  VB does not get automatic properties, so they are left with the more verbose version of the syntax.

Partial Methods

Partial Methods are very useful for light weight event handling in generated code.  For instance, lets assume that you had a generated class that looked like this:

Partial Class NewFeatures
Partial Private Sub BeforeTextChange(ByVal oldText As String, ByVal newText As String)
End Sub
 
Partial Private Sub AfterTextChange(ByVal oldText As String, ByVal newText As String)
End Sub
 
Private _text As String
Public Property Text() As String
Get
Return _text
End Get
Set(ByVal value As String)
BeforeTextChange(_text, value)
_text = value
AfterTextChange(_text, value)
End Set
End Property
End Class

image The partial methods BeforeTextChange and AfterTextChange are convenient extension points should the person using your generated code needs to hook into them, but the magic is that any of these methods which are not given implementations (both in our case above) get compiled away.  On the right you can see the Reflector disassembly for Text property.  Note that there are no calls to the partial methods, because the compiler did not emit IL for them since there were no implementations.

Now let's add the following short code-snippet into our project:

Partial Class NewFeatures
Private Sub BeforeTextChange(ByVal oldText As String, ByVal newText As String)
newText += oldText
End Sub
End Class

image With this added, we can go examine the Reflector disassembly again, and this time we see something very different.  Now we see the call to BeforeTextChange but still no AfterTextChange because it still has no implementation.

Now, some important notes about this feature.  Partial Methods must be Subs and they must be Private.  This is to avoid them being compiled away either changing your interface (private) or breaking other code which depends on its results (hence no functions).

Implicitly Typed Variables

Implicitly typed variables are not variants, this is very important so I'll repeat myself, Implicitly typed variables are not variants.  These are strongly typed variables which you simply forgo the need to type (as in press keys) the type (as in the class name).

The restrictions?  You must initialize the object on the same line it is declared, so that the compiler can infer the type.  Here is an example:

Dim myString = "This is a string, I swear"

Now myString is a System.String, not a System.Object or anything else. 

Object Initializers

This is a minor tweak to something which VB has always been better at than C#.  It makes a more compact version of the With syntax, at the cost of adding curly braces into VB, so you can judge if it's worth it for yourself.

Sub Main()
Dim ds = New SqlClient.SqlConnection() _
 With {.ConnectionString = "Blah"}
End Sub

For C# this feature is a god send, but C# didn't always have With, so it's your call if this is truly a great feature.

Anonymous Types

Now, the addition of With as part of an object initializer is a little ho-hum, but this is not.  Enter Anonymous Types, a strongly typed object where the type is not explicitly declared, but rather implicitly declared.

Sub Main()
Dim ds = New With {.FirstName = "Tim", _
 .LastName = "Rayburn"}
End Sub

image Ok, have I blown your mind yet? No? Well, then try this in for size... On the right is the Intellisense you receive when you type "ds." with this variable in scope.  The compiler has converted out simple syntax above into a full type with two properties : FirstName and LastName.  Pretty darned sexy if you ask me.

Restrictions?  Of course there are restrictions.  These can only be used as private or local variables.  If any other type will ever see this object them you have to convert this to a full class.  The VB compiler will let you make these public, but it emits the type as System.Object and you loose intellisense.

Embedded Xml

This is a feature that C# 3.0 does not have, it is solely the province of Visual Basic and I must admit, it kind of rocks.  But it will also break your head the first time you read it:

Sub CreateCityXml(ByVal name As String, ByVal lat As Double, ByVal lon As Double)
Dim cityXml As XElement = _
<City>
<Name><%= name %></Name>
<Latitude><%= lat %></Latitude>
<Longitude><%= lon %></Longitude>
</City>
 
cityXml.<City>.<Longitude>.Value = "XXX"
End Sub

This feature has to do with LINQ to XML, the basic object of which is the XElement class we are declaring above.  You can with this embed XML directly in your VB code.  Notice there are no line continuation characters after the root node opens, this is because it is assumed that the declare will end when the root node is closed.  Also note the use of the <% and %> like ASP and ASP.NET use to embed code into the XML.  This simple example is simply outputting variables, but there is no reason why this couldn't just as easily have contained a For loop or some other more complex code.

The final line before the end of the sub shows how you can also use the XML node syntax as if they were an object model.  Now this does not include Intellisense support for the .<tag> names, but it is still pretty slick.

Lambda Expressions

I know that Visual Basic has a tradition of being a less terse, more verbose language, but I personally feel that VB got the short end of the stick on Lambda Expression syntax.  A Lambda expression is supposed to be a terse syntax for anonymous delegates which also happens to be able to be explored via code if you're using Expression Trees (which we will not discuss here).  For instance, let's assume that you wanted to select items from an List(of Integer) where the value was greater than 50.  You could write code like this:

Function GreaterThan50(ByVal inputList As List(Of Integer)) As List(Of Integer)
Return inputList.Where(Function(i) i > 50)
End Function

This is much more verbose than the C# syntax for that Lambda Expression "i => i > 50" but I will grant you it is more readable so hopefully people who prefer VB will prefer the VB syntax.

Extension Methods

The best feature of the .NET Framework 3.5, hands down, is extension methods.  If anyone has sold you on LINQ as the best feature, laugh at them and remind them that LINQ is entirely based on extension methods.

What are they?  Simple : The ability to add a new method to an existing type which is only visible to those who implement your extension library.

Restrictions? Some.  The biggest is that you do not get access to anything you wouldn't have had access to already.  So creating an extension method is not going to allow you to get access to private or internal types for a class.

Benefits? Huge!  As cool as being able to add new methods to classes is, you'll please note I said you could extend types!  This means you can create an Interface and then provide implementation for that interface via extension methods.  In fact, that's how LINQ is done in great part.  The .NET Framework now contains extension methods such as "Where" and "First" and "GroupBy" for the IEnumerable interface.  As such any IEnumerable can use these, without changing the interface at all.

Very important note to those who try to stay fluent in both languages, the VB syntax for extension methods is very different than the C# syntax, you'll want to pay very close attention to this.

Here are two examples, one extends a class, the other an interface:

<Extension()> _
Function ToStringNullSafe(ByVal inObj As Object) As String
If inObj Is Nothing Then
Return String.Empty
Else
Return inObj.ToString()
End If
End Function
 
<Extension()> _
Sub Dispose(ByVal inObj As IDisposable)
If inObj IsNot Nothing Then
inObj.Dispose()
End If
End Sub

The first of these extension methods is something every UI developer has wished for, a ToString function which does not blow up just because the variable is Nothing.

The second is an ingenious (if I say so myself) and beautiful hack of the IDisposable interface.  Most, but importantly not all, objects which implement IDisposable implement a public Dispose method.  Some however do not, even though they implement it explicitly.  This method will add a public Dispose method to any object which implements IDisposable.

What if they already have one you ask?  The actual method on an object always wins out, and if there is a danger to extension methods, that is it.  Should the person who controls that type add a method which has the same name as your extension method, your extension method becomes uncallable.  A minimal risk for the incredible power of being able to provide implementation to interfaces.