Visual Basic 10.0的新特性

Jonathan Aneja, Program Manager
Lucian Wischik, Software Engineer/Specification Lead
Paul Vick, Principal Architect
November 08

内容
序言. 1
语言新特性 (New Language Features). 2
  多行 lambda (Multiline Lambdas). 2
    Sub lambda (Sub Lambdas). 3
    单行的 Sub lambda (Single-line Sub Lambdas). 3
  隐式续行 (Implicit Line Continuation). 3
  自实现属性 (Auto-implemented Properties). 6
  集合初始化器 (Collection Initializers). 7
  数组字面量 (Array Literals). 7
  可空可选参数 (Nullable Optional Parameters). 8
  范型变异 (Generic Variance). 8
    协变 (Covariance). 8
    逆变 (Contravariance). 9 
    约束 (Limitations). 9
  动态语言互操作 (Interop with Dynamic Languages). 10
  无PIA编译 (Compiling without PIAs). 10
与C#的关系 (Relationship with C#). 11
资源 (Resources). 12



Visual Basic一直致力于对成为最具效率的大型商业程序或以数据为中心的语言工具.该语言的9.0版本包括语言集成查询(LINQ),最好的XML支持,以及其他一些核心语言特性如可空类型.从那后Visual Studio的托管语言团队一直努力于下一个版本的Visual Basic -第10版.  该版本的开发焦点是添加具有生产力的特性到语言中,以让开发者可以用更少的代码完成更多的事情.
然而此文档描述的特性是当前预想的,许多东西有可能会在产品周期中改变,还有些则要看用户反馈.我们很期望你使用Visual Studio 2010 CTP来测试特性让我们知道你想什么。由于VS是CTP的,所以质量不会很好,并且不稳定,请期待最终发布。
(无聊的我不译了。。。)

语言新特性


    多行 Lambda
多行lambda是一个扮演Function的lambda表达式,它包含一个或多个语句.
    Dim nums() As Integer = {1, 2, 3, 4, 5}

    nums = Array.FindAll(nums, Function(n)
                                   Console.WriteLine("testing " & n)
                                   Return n > 2
                               End Function)

就像常规的lambda表达式一样,编译器如果可能将会推断每个参数的类型(此例中推断n为Integer).编译器也会使用显式类型算法来选择Return语句中的返回类型从而推断lambda的返回类型,如:

   'numDelegate 是一个与 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

此列中,编译器发现返回类型要么是Integer要么是Double,所以它选择了Double这个更大的并且可以包含任何Integer的类型.

作为选择,你可以通过使用As子句来明确指定你所期望的返回类型,此例中,编译器将只使用Single而不去尝试推断返回类型:

    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
就像Function关键字可以创建一个多行Lambda并且返回值,Sub关键字则可以用来创建一个多行Lambda而不返回值:
    Array.ForEach(nums, Sub(n)
                            Console.Write("Number: ")
                            Console.WriteLine(n)
                        End Sub)

单行的 Sub Lambdas
Visual Basic 9.0 只支持返回值的一个Lambda表达式;如以下行将会报错:

    'Error - Console.WriteLine 不返回值
    Array.ForEach(nums, Function(n) Console.WriteLine(n))

在 Visual Basic 10.0 中, lambda可以包含不返回值的表达式:
    Array.ForEach(nums, Sub(n) Console.WriteLine(n)) '有

隐式续行
下划线字符一直被用于Visua Basic来指示当前逻辑行被分离成一个或多个物理行。Visual Basic 10.0中不再需要下划线,对下划线的需要是被推断的(也就是续行符变成隐式的) .当然,对下划线的需要并未完全从语言中移除, 隐式续行的目的只是为了减少开发者大量实用续行符的需求
在高级层,续行符在以下情况隐式:
ft=,,Calibri]1.       在attribute 后(这个译法有很多:特性\属性(Attribute)\我喜欢译为元属)
2.       逗号后
3.       点后 (也就是方法调用)
4.       二进制算子后 (After a binary operator)
5.       任何一个Linq查询子句后 (After a LINQ query clause)
6.       (  { 或<%= 后
7.       )   }  或 %> 前

以下代码说明何地隐式续行会被发生:
   <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

以下符号说明续行发生的位置:

符号 前 后 (x表示不支持)
,   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 initializer)  X
Group By X X
Group Join X X
Join X X
Let X X
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 binary)   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
<> Operator   X
Is Operator   X
IsNot Operator   X
Like Operator   X
& Operator   X
And Operator     X
Or Operator    X
Xor Operator    X
AndAlso Operator   X
OrElse Operator   X
<< Operator    X
>> Operator   X

自实现属性

开发者通常需要创建一个实体类或者容器来容纳数据,以下定义了一个最简单的属性:

 

        Private _FirstName As String

 

        Property FirstName() As String

            Get

                Return _FirstName

            End Get

            Set(ByVal value As String)

                _FirstName = value

            End Set

        End Property

 

 

自实现属性提供了简单的单行途径来表达这个概念:

 

        Property ID() As Integer

        Property FirstName() As String

        Property LastName() As String

 

 此例中,编译器讲会生成一个与该属性同名的后台字段,同时会在该字段前加个下划线,它会被同时应用到该属性的获取器与设置器上。

 

初始化器会给一个自实现属性安排一个默认值(在调用类的构造器设置):

 

    Property ID() As Integer = -1

    Property SupplierList() As New List(Of Supplier)’注:这里可以像一个字段一样初始化。

 

    Property OrderList() As New List(Of Order) With {.Capacity = 100‘注:从With开始的语法是VB2008中加的 ,称为类型初始化器

 

 <DefaultValue("-")>

    Property Name() As String Implements ICustomer.Name‘注:实现接口,标记元属

 

 自实现属性不能有形参,同时也不能被申明为ReadOnly WriteOnly(遗憾)。

 

 

 

集合初始化器

集合初始化器提供一种方式来初始化集合类型并可以在单表达式中提供以一系列的默认值,如:

 

  Dim list = New List(Of String) From {"abc", "def", "ghi"}

’注:在VB中,这里还可以有另外2种语法

 

   'Dim list As New List(Of String) From {"abc", "def", "ghi"}

 

   'Dim list As List(Of String)= New List(Of String) From {"abc", "def", "ghi"}

 

'后两种都是显式告诉编译器类型:变量listList(Of String),也就是进行强类型说明。

 

‘而作者给的例子是用了VB2008中的新语法功能:局部变量类型推断

 

’如:Dim i =100,i 就被推断为Integer类型,Dim d =3.14,d被推断为Double。因为字面数值常量的默认类型是integer Double

 

 

 

每个From关键字后的元素将会被传递到该集合类型的Add方法,等同于如下:

 

    list.Add("abc")

    list.Add("def")

    list.Add("ghi")

 

 

相似地,字典类型可以这样初始化:

    Dim list As New Dictionary(Of Integer, String) From

                                                        {{1, "abc"},

                                                         {2, "def"}}

 

当在From关键字后的元素被嵌套,编译器会展开每支架中的元素,然后依次如下调用:

        list.Add(1, "abc")

        list.Add(2, "def") 

 

 

开发者可以自由地提供自己的Add实现,要么作为一个类型的实例方法,要么作为扩展方法:

 

    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

 

 

 ’注释:扩展方法是VB2008(9)\C#3 .Net Framework 3.5的实现,通过定义一个静态方法扩展到某类型,然后可以像实例方法调用该扩展方法。

 

    <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 

 

 

字面数组

字面数组提供简单的语法来申明数组,它的类型被编译器推断。

 

    Dim a = {1, 2, 3} '推断为Integer()

    Dim b = {1, 2, 3.5} 推断为 Double()

    Dim c = {"1", "2", "3"} '推断为 String()

    Dim d = {1, "123"} '推断为 Object() (Option Strict On则会警告) 

 

嵌套的数组字面量用来录制多维数组:

 

    Dim e = {{1, 2, 3}, {4, 5, 6}} '推断为 Integer(,)

    Dim f = {({1, 2, 3}), ({4, 5, 6})} '推断为Integer()() (交错数组) 

 

 

可空可选参数

可选参数现在可以被定义为Nullable并可以初始化值:

 

    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#.)

 

泛型的一方面常常长人惊讶如以下语句是非法的:

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

    Dim objects As IList(Of Object) = strings'注:在编译时可以通过,而在运行时会抛出InvalidCastException,即无效转换异常

 

 

 

第二个分配是不允许的,因为strings没有与objects同样的元素类型。这是最完美的解释。如果允许的话,你可以这样写:

 

    objects(0) = 5

    Dim s As String = strings(0)

 

这将可以允许一个Integer被插入到String的列表中,随后又被萃取为String(注:把Integer转为String,这个转换总是安全的),这会破坏类型安全。

 

然后,以上情况在有些接口不会发生,明显地,根本没有办法插入一个对象到集合。就如接口IEnumerable(Of T)

 

    Dim objects As IEnumerable(Of Object) = strings正确执行

 

根本没有什么办法可以让错误种类的东西投放,如objects放到strings,因为objects不包含可以取元素的方法,特变(Variance)可以允许如该情况下的安全分配。结果就是与以上情况相似的条件都可以工作了。

 

协变Covariance

.NET 4.0 IEnumerable(Of T) 接口可以像这样申明:

 

    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 

 

Out 在这个申明中意味着T只能存在于该接口的输出位置--否则编译器会抱怨。在该约束的返回中,该接口成为T的协变,这意味着A如果有个引用转换到B,那么IEnumerable(Of A) 被作为IEnumerable(Of B)对待。

 

最终,任何一连串的string也成了一连串的object。这在LINQ中的许多情况很有用。例如:

 

    Dim result = strings.union(objects) 'Succeeds with IEnumerable(Of Object)

 

这在上一个版本中不允许的,你不得不得做许多笨重的包装来让2个集合有同样的元素类型。

 

逆变Contravariance

类型参数可以有一个In修饰符,限制他们只能在输入位置。一个关于IComparer(Of T) 例子:

 

    Interface IComparer(Of In T)

        Function Compare(left As T, right As T) As Integer

    End Interface

 

稍微有点让人困惑的结果是一个 IComparer(Of Object) 实际上是被看作一个 IComparer(Of String)!你这样想可以合理的解释原因:如果一个比较器可以比较2个对象,它自然也可以比较2个字符串。该性质涉及到了逆变。

 

泛型类型的参数可以同时有In和Out修饰符,如泛型委托类型Func:

 

    Delegate Function Func(Of In TArg, Out TResult)(arg As TArg) As TResult

 

显然,参数只能进,结果只能出。 所以 Func(Of Object, String) 实际上可用作 Func(Of String, Object)。

 

Limitations

因为是在CLR中,所以特变类型参数只能出现在接口和委托类型的申明中。 特变只应用到类型参数间的引用转换。如,一个IEnumerable(Of Integer) 不是IEnumerable(Of Object),因为从Integer到Object的转换是一个装箱转换,而不是引用转换。

 

  

 

与动态语言交互Interop with Dynamic Languages

  

从历史的角度看,Visual Basic 是一个兼顾了静态类型的安全性和性能却缺少动态类型的灵活性的语言。动态语言运行时(DLR)可以让它与动态语言以这样的方式更简单地交互:每个对象从各自的源生语言维护自己的语义。

  

过去的几年,一些复兴的开发者对动态语言(如Python/Ruby)及它们附带的库或架构感兴趣。这些语言和架构可以使用 DLR IDynamicObject 接口来定义动态操作的意义,或是某些情况下某API允许直接通过属性语法来访问一个对象的属性(一个好的例子是 SliverLight 中的 HTML DOM)。

 

延迟绑定将会继续以之前的 Visual Basic 同样方式工作,但是延迟绑定器自身将会被升级,以便在某对象实现了 IDynamicObject 接口的情况下可以识别该对象。这将允许 Visual Basic 开发者可以完全地与像 IronPython IronRuby 这样的动态语言互操作,只要API实现了 IDynamicObject

 

 以下代码调用名为 "randon.py" Python库中的一个方法:

 

    Dim random As Object = python.UseFile("random.py")

    Dim items = {1, 2, 3, 4, 5, 6, 7}

    random.shuffle(items)

 

小弟水平有限,翻译不好的地方还望指正。

posted on 2010-11-27 13:17  cyclone_dll  阅读(783)  评论(2编辑  收藏  举报