Está en la página 1de 13

New features in Visual Basic 10

Jonathan Aneja, Program Manager

Lucian Wischik, Specification Lead

Paul Vick, Principal Architect

January 28, 2011

Contents
Contents..................................................................................................................... 1
Introduction................................................................................................................ 2
New Language Features.............................................................................................2
Multi-Line Statement Lambdas................................................................................2
Sub Lambdas........................................................................................................3
Single-line Sub Lambdas......................................................................................3
Uses of statement lambdas..................................................................................4
Implicit Line Continuation........................................................................................4
Auto-implemented Properties..................................................................................7
Collection Initializers...............................................................................................7
Array Literals...........................................................................................................8
Optional Parameters Default To Nothing.................................................................9
Generic Co- and Contra-variance............................................................................9
Limitations..........................................................................................................11
Interop with Dynamic Languages..........................................................................11
Compiling without PIAs..........................................................................................12
Resources.................................................................................................................13

[1]
Introduction
We are proud to release Visual Basic 10, the latest version of the Visual Basic
language. This is the version of the language that ships with Visual Studio 2010
and .NET 4.

Microsoft has committed to a policy of “co-evolution” between Visual Basic and C#,
where major new features will appear in both languages at the same time, and
important new features that appear in both languages in this release include interop
with the Dynamic Language Runtime, and the ability to build solutions that no
longer require Primary Interop Assemblies to be deployed on end-user machines.

Some new features in this version of the language, such as implicit line
continuations, provide a cleaner or simpler syntax that will be used in almost every
function you write. Other new features, such as statement lambdas, enable
powerful idioms in new Microsoft frameworks such as Silverlight 4 and the Task
Parallel Library.

Visual Basic 10 also marks the first release in which the language specification is
deployed with the product. It can be found in C:\Program Files (x86)\Microsoft Visual
Studio 10.0\VB\Specifications.

Visual Basic has always strived to be the most productive tool for building line-of-
business, data-centric applications. Version 9.0 of the language delivered Language
Integrated Query (LINQ), first-class XML support, as well as other core features such
as nullable types. We are proud to release Visual Basic 10, which makes the
language cleaner and simpler and more powerful.

New Language Features


Multi-Line Statement Lambdas
A statement 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)

[2]
Just like regular lambdas, the compiler will infer the type of each parameter where
possible (in this case inferring n as Integer). The compiler will also infer the
lambda’s return type by using the dominant type algorithm (see section 8.13 of the
Language Specification, usually at “C:\Program Files (x86)\Microsoft Visual Studio
10.0\VB\Specifications”) to choose between the types of each expression in a
Return statement. For example:

'numDelegate is an anonymous delegate compatible with Func(Of Integer,


Double)
Dim numDelegate = Function(n As Integer)

If n Mod 2 = 0 Then
Return 3
Else
Return 3.14
End If

End Function

In this case, the compiler sees that the return type could be Integer or Double, and
so it picks Double as it is a wider type that can encompass any Integer.

Alternatively, you can explicitly specify the return type you want by using an As
clause. In this case, the compiler will just use “Single” and will not attempt to infer
a return type:

Dim lambda = Function(n As Integer) As Single


If n Mod 2 = 0 Then
Return 3
Else
Return 3.14
End If
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, lambdas can now contain a single statement:

[3]
'Valid
Array.ForEach(nums, Sub(n) Console.WriteLine(n)) 'Valid

Uses of statement lambdas


One important use of multiline lambdas is in Silverlight applications for
asynchronous operations. For instance,

Dim client As New WebClient


AddHandler client.DownloadStringCompleted,
Sub(sender As Object, e As DownloadStringCompletedEventArgs)
If Not e.Error Is Nothing Then Return
MessageBox.Show(e.Result)
End Sub

client.DownloadStringAsync(New Uri("http://blogs.msdn.com/lucian"))

Note: to create Silverlight projects you have to download the Silverlight 4 SDK. Also,
read on that site why Silverlight’s protection against cross-site scripting attacks will
cause it to throw a SecurityException, and how to use a file “clientaccesspolicy.xml”
to make it work.

Another important use of statement lambdas is in the new Task Parallel Library. For
instance,

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


nums.AsParallel.ForAll(Sub(n) Console.WriteLine(n))

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 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

[4]
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

The following tokens carry an implicit line continuation:

Token Befor Afte


e r
, X
( X
) X
{ X
} X
<%= X
%> X
< (in an attribute) X
> (in an attribute) X
Aggregate X X
Distinct X X
From (in a query) X X
From (in a collection X
initializer)
Group By X X
Group Join X X
Join X X
Let X X

[5]
Order by X X
Select (in query context) X X
Skip X X
Skip While X X
Take X X
Take While X X
Where X X
In X X
Into X X
On X X
Ascending X X
Descending X X
^ Operator X
* Operator X
/ Operator X
\ Operator X
Mod Operator X
+ Operator (unary and X
binary)
^= Operator X
*= Operator X
/= Operator X
\= Operator X
+= Operator X
-=Operator X
<<= Operator X
>>= Operator X
&= Operator X
< Operator X
<= Operator X
> Operator X
>= Operator X
= Operator X
<> Operator X
Is Operator X
IsNot Operator X
Like Operator X
& Operator X
And Operator X
Or Operator X
Xor Operator X

[6]
AndAlso Operator X
OrElse Operator X
<< Operator X
>> Operator X

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:

[7]
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()

[8]
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)

An array literal always takes its type from the context, if applicable:

Dim g As = IEnumerable(Of Object) = {1, 2, 3} ' uses Object()


GetType(String).GetConstructor({}).Invoke({}) ' uses Type() then Object()

Sub test(ByVal x As Double())


End Sub

test({1, 2, 3}) ' uses Double()

Only when the context doesn’t say which type to use, will the type of the array be
inferred from its elements.

Optional Parameters Default To Nothing


Optional parameters can now be of any type, including Nullables and Value types:

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)

Sub Test(x As IntPtr = Nothing)

An optional parameter can be initialized either with a constant (if the type of the
parameter is compatible with that constant), or with the “Nothing”. Note that
“Nothing” is the only expression that can be used to initialize a user-defined class or
structure.

Generic Co- and Contra-variance


The following code is now legal in Visual Basic 10:

Dim strings As IEnumerable(Of String) = New List(Of String)


Dim objects As IEnumerable(Of Object) = strings

Intuitively it makes sense, on the grounds that “if someone asks to enumerate
through a collection of objects, and I give them my collection of strings, it should be
fine since String inherits from Object.” This is called covariance.

Similarly, the following code is now legal in Visual Basic 10:

[9]
Dim f As Action(Of Object) = Function(o As Object) Console.WriteLine(o)
Dim g As Action(Of String) = f

The intuition here is that “if this action has the power to print out any object, and
someone asks just for an action which has the power to print any string, it should be
fine since String inherits from Object”. This is called contravariance.

What has changed to allow these examples is that some key interfaces and
delegates in the .Net framework are now declared with the “Out” and “In”
keywords:

Interface IEnumerable(Of Out T)


Delegate Sub Action(Of In T)

The “Out” keyword here means that IEnumerable(Of Type1) can be widened to
IEnumerable(Of Type2) so long as Type1 has a widening reference conversion to
Type2. For instance, String has a widening reference conversion to Object, and
ArgumentException has a widening reference conversion to Exception.

Note that this conversion from IEnumerable(Of Type1) to IEnumerable(Of Type2) is


efficient: it is basically free at runtime. This is different from the old way of doing
the conversion, e.g. “strings.Cast(Of Object)()”, which involved the runtime cost of
iterating through every element in the collection and casting it.

The “In” keyword works in reverse. Here it means that Action(Of Type1) can be
widened to Action(Of Type2) so long as Type2 has a widening reference conversion
to Type1.

The keywords “Out” and “In” are only allowed in interface and delegate
declarations. Here is an example which combines both:

Interface ITest(Of Out TO, In TI)


Function a() As TO
Sub b(ByVal x As TI)

ReadOnly Property c() As TO


WriteOnly Property d() As TI

Sub e(ByVal x As Action(Of TO))


End Interface

For reasons of type safety, the “Out” generic type parameters may only ever be
used in output positions, e.g. as the return type of a function or as the type of a
readonly property. And the “In” generic type parameters may only ever be used in
input positions, e.g. as the type of an argument or the type of a writeonly property.

It is subtle, the exact definition of what makes an input or output position - as


illustrated by “Sub e” above! The best way to understand the feature is to
experiment hands-on with the language, or read section 4.9.3 of the Visual Basic

[10]
Language Specification (installed at C:\Program Files (x86)\Microsoft Visual Studio
10.0\VB\Specifications).

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.

When writing your own frameworks and classes, our guidance on co- and contra-
variance is to use it only if doing so doesn’t involve creating extra interfaces. For
instance, .Net4 introduces a readonly class called “Class Tuple(Of T1,T2)”. It is
readonly, and so only uses T1 and T2 in output positions, and so they could have
been marked with the Out keyword. But Tuple is a class: the only way to allow
covariance would be through an extra “Interface ITuple(Of Out T1, Out T2)” which
Class Tuple then inherits from. We decided not to do this: it is not worth introducing
extra interfaces for the sole purpose of co- or contra-variance.

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 continues to work the same way it always has in Visual Basic, but the
latebinder itself has been updated to recognize when an object implements the
IDynamicObject interface. This allows 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) ' requires Option Strict Off

[11]
And this example uses one of the new DLR classes:

Dim bag As Object = New Dynamic.ExpandoObject


bag.x = 15 ' dynamically adds a new field called “x”
bag.y = 27 ' (requires Option Strict Off)
Console.WriteLine(bag.x + bag.y)

An important use of DLR Interop is in Silverlight 4. For instance,

Dim doc As Object = Windows.Browser.HtmlPage.Document


Dim e = doc.getElementById("item") ' requires Option Strict Off
e.innerText = "hello world"

Compiling without PIAs


Using .NET to program against the Microsoft Office Object Model used to require the
use of Primary Interop Assemblies (PIAs), which had to 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 allows 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.

In order to turn on this feature, select the reference in Solution Explorer and then
set “Embed Interop Tyeps” to “True” in the Properties window:

[12]
Resources
For more information, visit the Visual Basic Team Blog
(http://blogs.msdn.com/vbteam) and the Visual Basic Developer Center
(http://msdn.com/vbasic). Have fun with Visual Basic 10!

[13]

También podría gustarte