RSS 2.0 Feed
2005-10 Entries
摘要:我在介绍Visual Basic 9.0的时候,曾经多次提到Tuple这个概念,当时是作为匿名类型的实例出现的。现在我们单独来讨论一下这个概念。Tuple常常译为“组元”,在大部分支持Tuple的语言中,常常表示成员数目确定,每个成员类型也确定的结构。常常用于表示函数的多个返回值或者查询的结果等。Tuple应当是强类型的,即所有成员的类型在编译时确定。比如,假想语法下 Dim t = New Tuple(Of String, Integer, Double) 那么t将具有三个成员,该数目无法改变;同时三个成员的类型分别为String, Integer和Double,也无法改变。如你所见,Tuple可以看作不用事先声明的结构体,可以根据所使用的场合灵活地创建。那么VB9和C#3的匿名类型当然是Tuple很好的实现方案。但是这都是N年后的东西了,我们在.NET 2.0中能否实现Tuple?最关键的难点在于,我们要在希望使用的地方创建Tuple的结构,而不是事先声明,因此就必须有个灵活的机制来完成。 方法一:TypeList 我是某一天在公共汽车上想到这个办法,后来看到和Loki的TypeList有相似之处。当然.NET没有特化和记录类型的能力,所以无法实现TypeList。但我们把静态类型运算的思路移到运行时,就可以做Typed Variable List——那就是Tuple。 public abstract class TypeNode { internal TypeNode {} }public sealed class Tail : TypeNode { }public sealed class Tuple<T, TNode> : TypeNode where TNode : TypeNode, new(){    public T Field = default(T);    public TNode Next = new TNode();} 我充分利用了.NET泛型的约束特性来达成我的设计。TypeNode被设计为abstract,因此约束了new()的泛型参数TNode将无法取值TypeNode本身的类型。而其internal的构造函数又限制了用户继承于它。这个手法就将TNode的取值范围限定在Tail和Tuple两个类型上。这个用法是我认为约束用法中相当巧妙的一种。 这个类型的原理很简单,就是利用泛型,在创建TypeList的实例时自动生成相同结构的链表。比如我们要创建一个String, Integer, Double的Tuple,就是这样写: Tuple<string, Tuple<int, Tuple<double, Tail>>> t; 如你所见,这种Tuple的类型参数第一个是某节点的类型,第二个要么是另一个Tuple,要么是Tail(表示终结列表)。这个对象创建出来以后就会自动生成一个“各个节点类型都不相同”的链表。 t = new Tuple<string, Tuple<int, Tuple<double, Tail>>>();t.Field = " a string ";t.Next.Field = 123;t.Next.Next.Field = 13.56; Tail没有Next字段,因此遇到Tail就代表Tuple终结了,这可以由编译器检查,因此没有越界的危险。而且这种Tuple可以达到无限长。不过这种方法也是有缺陷的,首先使用的语法方面非常不便,如果要用第7个字段,要写成myTuple.Next.Next.Next.Next.Next.Next.Field,稍不注意就会写错。无论VB还是C#都没有足够的抽象能力简化这一操作。第二个缺陷是建立Tuple时的一连串new操作开销很大,因为这里的new是通过反射进行的。所以受限于语言特性的缺乏,这种方法无法达到很完美的地步,不过这个思路也许在其他场合可以用上。 方法二:重载原型 模仿泛型委托的思路,我们可以用完全泛型化的一系列同名结构来模拟即时创建的Tuple: struct Tuple<T0>{    public T0 Field0;}struct Tuple<T0, T1>{    public T0 Field0;    public T1 Field1;}struct Tuple<T0, T1, T2>{    public T0 Field0;    public T1 Field1;    public T2 Field2;}......struct Tuple<T0, T1, T2, T3, T4, T5, T6,......[阅读全文]

posted @ | Feedback (7) | Filed Under [ 技术随笔 灵感记录 ]

摘要:本期是Visual Basic 9.0前沿播报动态篇的第三篇,也是这个系列的完结篇。按照惯例,我将Visual Basic 9.0最激动人心的部分放在了这一篇。在这一篇,我们将看到所有新特性作用在XML上之后带来的革新性变化。 Visual Basic 9.0专门为XML集成设置了一个开发组,力求将XML语言与Visual Basic语言完全结合,使Visual Basic成为全行业对XML支持最佳的开发工具。这些新特性都基于微软的XLinq——新一代支持语言集成查询的XML框架。使用XLinq可以按照XML逻辑树状对象模型来建立和访问。本文不打算介绍XLink,有兴趣可以下载这篇文档http://msdn.microsoft.com/VBasic/Future/XLinq%20Overview.doc。我要介绍的是,VB9为XLinq所做的惊人语法。 XML字面量 你有没有想过在一种编程语言里创建XML可以达到多么简单?VB9支持直接XML文档的原始结构作为字面量,也就是说,VB9里可以直接写: Dim x = <Books><Book author="A. S. Tanenbaum">Mordern Operating Systems</Book></Books> 这么写,VB不仅仅吧它当作一个字符串,而是可以帮你做XML结构的检查,而且编译器了解这一XML的结构,因此会有智能感知的帮助。你可以将XML字面量分成多行编写,直到遇到根元素的终结(例子中的</Books>)才判断XML字面量写完,因此无须使用续行符。这也就是说,VB的XML可以表达一个以单元素为根的XML结构片断。如果XML字面量仅仅是这样,就没有多大意思了。我们可以让这个XML字面量中的数据动态化: Dim rootName = "Books"Dim b As New Book {Author := "A. S. Tanenbaum", Title := "Mordern Operating Systems", ID := 20 }Dim x = <(rootName)><Book author=(b.Author)><%= b.Title %></Book></> 我们观察一下上面的代码,元素名称Books可以用变量来指定,只要在括号组成的“洞”填入即可,相应的关闭标记则变成</>这很重要,因为元素名称已经是动态决定的了,所以引入特定写法根据位置来关闭相应标记。我们看到,attribute的值也可以用洞来填入(attribute的名称也可以用相同语法),但是标记的Inner Text部分则不能使用洞,而是要使用<%= %>这种类似于ASP.NET数据绑定的语法,这称为代码嵌入。 这已经很强大并且激动人心了,不是吗?但还不够,我们可以把查询包含的语法嵌入到XML字面量中。假设我们有一组Book要生成: Dim books = GetBooks() '假设用别的代码生成了Book类型的集合Dim x = _<(rootName)>  <%= Select     <Book author=(b.Author)><%= b.Title %></Book>  From b In books Where b.ID > 5 %></> 我们用代码嵌入的手段,将类似于SQL的查询包含直接插入到XML字面量中去了。其结果很显然,是生成了<Books>下<Book>的列表。使用XML字面量,我们可以非常灵活地组合和生成我们想要得XML;也可以把XML直接拷贝粘贴到VB的IDE中,稍加修改而成为你自己的XML生成器。XML字面量还完善支持XML的namespace等特性。有了VB9,还需要XSLT吗?难说…… XML后期绑定 现在我们有了生成XML的手段,那么访问XML的手段呢?Visual Basic 9.0提供了XML后期绑定,我们可以用最简单的语法来访问XML。假设我们有刚才生成的Books文档,则可以用下列语法直接访问到它的某一个Book Dim title = x.Books.Book(0).InnerTextDim author = x.Books.Book.@author 这语法很类似于XPath,我们还可以做到XPath的//的功效: For Each Dim book In x.Books...Book    '遍历每一个Book元素Next 只要3个点,就可以把Books下边所有层次的Book都找到,然后直接就可以遍历。当然我们还可以用查询包含,使用SQL语法来查询XML文档。总之,在Visual Basic 9.0中使用XML会是一种前所未有的体验。 现在Visual Basic 9.0的新特性已经介绍完了,这确实是一个有着巨大进步的版本,同时特别注重用户体验的改善,保持着简单易用的特点。...[阅读全文]

posted @ | Feedback (13) | Filed Under [ 技术随笔 Visual Basic 9.0 前沿播报 ]

摘要:在谈到动态语言与静态语言的区别时,有一句很经典的话:Static typing when possible, dynamic typing when needed。Visual Basic支持后期绑定和动态标识符,因此完全可以按照对象的运行时类型进行操作。只是后期绑定或动态标识符缺乏对参数或返回值类型的约束,仅仅按照成员的名称进行操作。举一个例子:在静态篇我们介绍过匿名类型,假设有3个匿名类型的实例(Tuple): Dim a = New { Name := "Robbins", Age := 25 }Dim b = New { Name := "Andrei", ID := 12, Address := "Beijing" }Dim c = New { Name := New NameType("Mark"), Title := "PM" } 如你所见,三个Tuple具有不同的类型,由于匿名类型没有办法实现接口,因此没有办法用统一的语法操作a和b相同的属性Name。用后期绑定可以统一访问Name属性,但是c的Name属性与a,b的不同,但是后期绑定却能让他们用统一的方式访问,这就让动态的隐患扩大了。有没有既可以动态访问成员,又有部分强类型的约束呢?Visual Basic 9.0引入了动态接口。动态接口与普通接口不同,类型无需声明实现动态接口,只要具有相应动态接口定义的成员即可转换为动态接口类型。这个特性也称为鸭子类型判定。因为流传这样一种动态语言类型判断的手法:如果一个东西走路像鸭子,说话也像鸭子,那它就是鸭子。动态接口的定义需要用Dynamic修饰符: Dynamic Interface IHasName    Property Name As StringEnd Interface 这个接口规定了一个String类型的属性,名为Name。任何类型的实例,只要具有String类型的属性Name,就被推定为实现IHasName: Dim a = New { Name := "Robbins", Age := 25 }Dim b = New Button() {Name := "Button1", Text := "Button1" }Dim ihn As IHasName = aihn.Name = "Haward"ihn = bihn.Name = "Button2" 尽管a的匿名类型和Button类型都没有声明实现IHasName接口,但他们都有类型为String名为Name的属性,因此都可以使用IHasName接口。动态接口提供了有类型约束和IDE智能感知的后期绑定,再次提高了Visual Basic动态编程的能力。不过要提示一点,动态接口并非类型安全性的特性。...[阅读全文]

posted @ | Feedback (9) | Filed Under [ 技术随笔 Visual Basic 9.0 前沿播报 ]