Visual Studio 2010 New Language Features
· Multiline Lambdas: A multiline lambda is a lambda expression that represents a function containing one or more statements.
|
Dim nums() As Integer = {1, 2, 3, 4, 5} nums = Array.FindAll(nums,Function(n) Console.WriteLine(“testing “ & n) Return n > 2 End Function) |
· Sub Lambdas: Just as the “Function” keyword can be used to create a multiline lambda that returns a value, the “Sub” keyword can be used to create a multiline lambda that does not return a value
|
Array.ForEach(nums, Sub(n) Console.Write(“Number: “) Console.WriteLine(n) End Sub)
|
· Single-line Sub Lambdas: Visual Basic 9.0 only supported lambdas that were a single expression that returned a value; for example, the following line was an error:
|
‘Error – Console.WriteLine doesn’t return a value Array.ForEach(nums, Function(n) Console.WriteLine(n))
|
With Visual Basic 10.0, lambdas can now contain expressions that do not return a value:
|
‘Valid Array.ForEach(nums, Sub(n) Console.WriteLine(n)) ‘Valid |
· Implicit Line Continuation: The underscore character is used in Visual Basic to indicate that the current logical line is being split up over one or more physical lines. Visual Basic 10.0 removes the requirement for an underscore to be present after certain tokens where its presence can be inferred (i.e. the line continuation character becomes “implicit”). While the need to use underscore has not been entirely removed from the language, the intention is that developers will not have to use it in the vast majority of lines they write.
At a high level, the line continuation character is implicit in the following situations:
1. After an attribute
2. After a comma
3. After a dot (i.e. for method invocation)
4. After a binary operator
5. After a LINQ query clause
6. After a (, {, or <%=
7. Before a ), }, or %>
The following code demonstrates some of the places where implicit line continuation can be used:
|
<Attribute()> Function Go( ByVal x As Integer, ByVal y As Integer, ByVal z As Integer ) Dim query = From n In { 123, 456, 789 } Order By n Select n + x
End Function |
· Auto-implemented Properties: Developers often need to create simple entity classes or containers for data, in which the properties defined follow a very simple structure:
|
Private _FirstName As String
Property FirstName() As String Get Return _FirstName End Get Set(ByVal value As String) _FirstName = value End Set End Property |
Auto-implemented properties provide a simple one-line way of expressing this concept :
|
Property ID() As Integer Property FirstName() As String Property LastName() As String
|
In this case the compiler will generate a backing field with the same name as the property, but with a preceding underscore. It will also fill in the property’s getter and setter.
Initializers can be used to give an auto-implemented property a default value (which gets set in the class’ constructor):
|
Property ID() As Integer = -1 Property SupplierList() As New List(Of Supplier) Property OrderList() As New List(Of Order) With {.Capacity = 100}
<DefaultValue(“-”)> Property Name() As String Implements ICustomer.Name
|
Auto-implemented properties cannot have parameters, nor can they be declared ReadOnly or WriteOnly.
· Collection Initializers: Collection initializers provide a way to initialize a collection type and provide it with a series of default values within a single expression. For example:
|
Dim list = New List(Of String) From {“abc”, “def”, “ghi”} |
Each element after the “From” keyword will be passed to the Add method on the type:
|
list.Add(“abc”) list.Add(“def”) list.Add(“ghi”) |
Similarly, Dictionaries can also be initialized this way:
|
Dim list As New Dictionary(Of Integer, String) From {{1, “abc”}, {2, “def”}} |
When the elements after “From” are nested, the compiler will “unpack” the elements inside each set of brace and pass them sequentially to a single Add call:
|
list.Add(1, “abc”) list.Add(2, “def”) |
Developers are free to provide their own implementation of Add, either as an instance method on the type or through an extension method:
|
Dim list As New List(Of Customer) From { {123, “Jonathan”, “Aneja”}, {456, “Lucian”, “Wischik”}, {789, “Paul”, “Vick”} }
Class Customer Property ID As Integer Property FirstName As String Property LastName As String End Class
<Extension()> Sub Add(list As List(Of Customer), ID As Integer, FirstName As String, LastName As String)
list.Add(New Customer With { .ID=ID, .FirstName=FirstName, .LastName=LastName } End Sub
|
· Array Literals: Array literals provide a compact syntax for declaring an array whose type is inferred by the compiler.
|
Dim a = {1, 2, 3} ‘infers Integer() Dim b = {1, 2, 3.5} ‘infers Double() Dim c = {“1″, “2″, “3″} ‘infers String() Dim d = {1, “123″} ‘infers Object() (warning with Option Strict On) |
Nested array literals can be used to produce multidimensional arrays:
|
Dim e = {{1, 2, 3}, {4, 5, 6}} ‘infers Integer(,) Dim f = {({1, 2, 3}), ({4, 5, 6})} ‘infers Integer()() (jagged array) |
· Nullable Optional Parameters: Optional parameters can now be typed as Nullable and initialized to a default value:
|
Sub Add(x As Integer, y As Integer, Optional z As Integer? = Nothing)
Sub Add(x As Integer, y As Integer, Optional z As Double? = 4) |
· Generic Variance: (VB and C# are introducing this feature simultaneously, and the implementations are practically identical. The following section is adapted from Mads Torgersen’s excellent write-up in the equivalent document for C#.) An aspect of generics that often comes across as surprising is that the following is illegal:
|
Dim strings As IList(Of String) = New List(Of String) Dim objects As IList(Of Object) = strings |
The second assignment is disallowed because strings does not have the same element type as objects. There is a perfectly good reason for this. If it were allowed you could write:
|
objects(0) = 5 Dim s As String = strings(0) |
This would be allowing an Integer to be inserted into a list of Strings and subsequently extracted as a String, which would be a breach of type safety.
However, there are certain interfaces where the above cannot occur, notably where there is no way to insert an object into the collection. One such interface is IEnumerable(Of T). If instead you say:
|
Dim objects As IEnumerable(Of Object) = strings |
There is no way we can put the wrong kind of thing into strings through objects, because objects does not have a method that takes an element in. Variance is about allowing assignments such as this in cases where it is safe. The result is that a lot of situations that were previously surprising now just work.
· Covariance: In .NET 4.0 the IEnumerable(Of T) interface will be declared in the following way:
|
Interface IEnumerable(Of Out T) : Inherits IEnumerable Function GetEnumerator() As IEnumerator(Of T) End Interface
Interface IEnumerator(Of Out T) : Inherits IEnumerator Function MoveNext() As Boolean ReadOnly Property Current() As T End Interface |
The Out in these declarations signifies that T can only occur in output position in the interface – the compiler will complain otherwise. In return for this restriction, the interface becomes “covariant” in T, which means that an IEnumerable(Of A) is considered an IEnumerable(Of B) if A has a reference conversion to B.
As a result, any sequence of strings is also e.g. a sequence of objects. There are many places in LINQ where this can be useful, for example:
|
Dim result = strings.union(objects) ‘Succeeds with IEnumerable(Of Object) |
This would previously have been disallowed, and you would have had to do some cumbersome wrapping to get the two sequences to have the same element type.
· Contravariance: Type parameters can also have an In modifier, restricting them to occur only in input positions. An example is IComparer(Of T):
|
Interface IComparer(Of In T) Function Compare(left As T, right As T) As Integer End Interface |
The somewhat baffling result is that an IComparer(Of Object) can in fact be considered an IComparer(Of String)! It makes sense when you think about it: If a comparer can compare any two objects, it can certainly also compare two strings. This property is referred to as contravariance.
A generic type can have both In and Out modifiers on its type parameters, as is the case with the generic Func delegate types:
|
Delegate Function Func(Of In TArg, Out TResult)(arg As TArg) As TResult |
Obviously the argument would only ever come In, and the result would only ever come Out. Therefore a Func(Of Object, String) can in fact be used as a Func(Of String, Object).
· Limitations: Variant type parameters can only be declared on interfaces and delegate types, due to a restriction in the CLR. Variance only applies when there is a reference conversion between the type arguments. For instance, an IEnumerable(Of Integer) is not an IEnumerable(Of Object), because the conversion from Integer to Object is a boxing conversion, not a reference conversion.
Also please note that the CTP does not contain the new versions of the .NET types mentioned above. In order to experiment with variance you have to declare your own variant interfaces and delegate types.
· Interop with Dynamic Languages: Historically Visual Basic has been a language that provides both the safety and performance of static typing along with the flexibility of dynamic typing. The Dynamic Language Runtime (DLR) makes it much easier for dynamic languages to interoperate with each other in such a way that each object maintains the semantics from its original language.
Over the past few years, there has been renewed developer interest in dynamic languages (such as Python/Ruby) and their accompanying libraries/frameworks. These languages and frameworks can use the DLR’s IDynamicObject interface to define the meanings of dynamic operations, or in the case of an API to allow direct access to an object’s properties through property syntax (a good example of this is the HTML DOM in Silverlight).
Latebinding will continue to work the same way it always has in Visual Basic, but the latebinder itself will be updated to recognize when an object implements the IDynamicObject interface. This will allow Visual Basic developers to be able to fully interoperate with dynamic languages such as IronPython and IronRuby, as well as APIs that implement IDynamicObject
For example, the following code calls a method defined in the Python library “random.py”:
|
Dim random As Object = python.UseFile(“random.py”) Dim items = {1, 2, 3, 4, 5, 6, 7} random.shuffle(items)
|
· Compiling without PIAs: Using .NET to program against the Microsoft Office Object Model requires the use of Primary Interop Assemblies (PIAs), which must be deployed to the end-user’s machine. These assemblies are often very large, so deploying them can often be a nuisance.
Visual Basic 10.0 will allow these applications to be deployed without requiring PIAs to exist on the user’s machine. It does this by generating “local types” that perform the interop calls to the COM library directly. These types are annotated by the compiler in such a way that the Common Language Runtime (CLR) can unify these types across assemblies. The compiler will not copy every type in the PIA into your assembly, just the ones you actually use.







May 13th, 2010 at 12:18 AM
Nice post. Your Blog is bookmarked by me. Regards
May 14th, 2010 at 4:09 AM
Just wanted to say I really liked the post. You have really put a lot of time into your content and it is just wonderfull!