装配中的脑袋

用程序装配大脑,再用大脑装配程序
随笔 - 118, 评论 - 1214, 引用 - 11

导航

关于

如果想发较大的信件,请用Ninputer @ gmail.com

不要在我的Blog评论中张贴广告,除非同意向我付款。

标签

每月存档

最新留言

广告

Visual Basic 9.0 前沿播报·动态篇(三)XML字面量和XML后期绑定啊

本期是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).InnerText
Dim 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 on 2005-10-12 09:23:00 by Ninputer  评论(13) 阅读(10588)

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 String
End 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 = a
ihn.Name = "Haward"
ihn = b
ihn.Name = "Button2"

尽管a的匿名类型和Button类型都没有声明实现IHasName接口,但他们都有类型为String名为Name的属性,因此都可以使用IHasName接口。动态接口提供了有类型约束和IDE智能感知的后期绑定,再次提高了Visual Basic动态编程的能力。不过要提示一点,动态接口并非类型安全性的特性。

posted on 2005-10-09 08:53:00 by Ninputer  评论(9) 阅读(8288)

Visual Basic 9.0 前沿播报·动态篇(一)动态标识符

动态语言今年来发展很快,各种脚本语言多少都带有些动态语言的特点。动态语言以其灵活的语法和丰富的运行时行为赢得了许多人的青睐。在.NET阵营,C#一直扮演着静态语言的角色,尽管3.0的语法改变很激进,但仍注重于编译时的类型检查和约束。动态特性用的不好会产生更多运行时问题,不易确保程序的可靠性,但其提高开发效率的作用是毋庸置疑的。Visual Basic 9.0是Visual Studio中唯一能让你统领动态和静态两大领域的语言,让你在程序中自由选择喜欢的风格。

Visual Basic 从1.0便支持后期绑定,即按照对象的运行时类型信息使用对象,而不是定义这个对象时的类型信息。如:

Dim l As Object = New ArrayList()
l.Add(12)
l.RemoveAt(0)

我们知道Object没有Add或RemoveAt方法,但运行时类型ArrayList具有他们,因此Visual Basic允许到运行时再检查有无相应的操作并支持。既然这个过程已经是在运行时做的了,我们就应该允许这个后期绑定的操作本身也是在运行时确定。这个语法增强叫做动态标识符。比如我们可以和这样写:

Dim l As Object = New ArrayList()
l.("Add")(12)
l.("RemoveAt")(0)

我们看到,这个时候方法名称Add和RemoveAt已经是字符串了,它当然也可以是包含字符串的变量!所以你甚至可以写出这样的代码:

l.(Console.ReadLine())(12)
l.("Remove" & "At")(0)

这样,作为方法名称的标识符就可以完全在动态期间确定了。方法名称如此,那么类型名称呢?理应如此。我们可以这样写:

Dim l As Object = New ("ArrayList")()

这样,你的变量l的类型将根据一个运行时字符串的值确定。动态标识符还能将函数的参数也动态化,假设有下列子程序:

Sub Method1(Optional arg1 As String, Optional arg2 As String)

运行的时候,我们可以动态地指定将数值赋给哪个参数:

If a > 0 Then argString = "arg1" Else argString = "arg2"
Method1({argString}:= a.ToString())

注意在:=符号之前的大括号,表示对参数名称的动态结合。有了动态标识符这一特性,Visual Basic 9.0将不需要利用反射的复杂语法,就可以做很多需要反射和运行时类型信息来做的任务,这使得Visual Basic成为解决你手边小问题的最佳帮手。本期我们已经领略到Visual Basic 9.0在动态特性上的革新,下一期将介绍第二个动态特性——动态接口。

posted on 2005-09-28 09:24:00 by Ninputer  评论(146) 阅读(9838)

Visual Basic 9.0 前沿播报·静态篇(六)松弛委托和可为空类型语法增强

本期介绍的两个VB9作为数据开发辅助功能的新特性。CLR在.NET 2.0增加了许多关于委托的新特性(但大部分都不为任何语言所支持),其中一个叫做协变的特性允许放松委托与函数绑定时的签名检查(C# 2.0支持)。为了追求更高的灵活性,VB9决定在协变的基础上再进一步,引入松弛委托的概念。主要是按照以下规则为委托的实例指定函数:

1、函数的参数个数和返回值类型与委托的签名相同
2、函数的参数类型与委托签名相应位置上的参数类型有父子类或接口-实现关系,或Visual Basic定义的隐式转换规则。

就是说,假如我们有个委托的签名是F(Integer),那么不仅可以为他的实例指定g(Integer)签名的函数,还可以指定g(Double)或者g(Object)签名的函数,因为Int32有到Double的隐式转换,而且是Object的子类。举个实际的例子:

Public Delegate Sub Test(arg As Integer) '在代码中 Sub Func(arg As Object) Console.WriteLine(arg.ToString()) End Sub Dim d As Test = AddressOf Func d(13)

可为空类型在VB2005中就已经支持,而且和C#一样可以与Object类型互转而不会出现语义不同问题。但是VB2005没有加入C#那些语法糖,如定义语法的简化、lifted运算符和空值判断运算符。虽然我觉得这些语法糖未必有多好吃,不过VB9最终还是添加了一些。首先是问号定义的语法。

Dim var1 As T? Dim var2? As T

以上两个定义是等价的,其意义是:当T为引用类型时,变量的类型为T;当T为值类型时,变量的类型为System.Nullable(Of T)。这样就将所有可为空类型的定义语法统一起来,进而可以用统一的方法判断空值。第二个引用的语法是lifted运算符:当T类型定义的运算符用于T?型时,将自动按以下规则计算:如果原运算结果类型为U,那么使用可为空类型运算的结果就是U?;参与运算的数中有任意一方为Nothing,结果就是Nothing。这样,多年阔别Visual Basic的Null传播又回来了。注意,没有以T?格式定义的引用类型,尽管可以为空引用,但是不会Null传播,只会抛出异常,这一点要注意。

VB9前沿播报的静态篇就到此结束了,从下一篇起,我们进入Visual Basic语法改进的动态篇。

posted on 2005-09-27 14:33:00 by Ninputer  评论(3) 阅读(6312)

Visual Basic 9.0 前沿播报·静态篇(五)查询包含

前面所介绍的Visual Basic 9.0新特性,初衷都是为了迎合.NET Framework新的数据框架——Linq。Linq的一个口号是“让查询无处不在”,它将类似SQL的语法强类型地引入到Visual Basic中,而且可以任意组合使用。不要以为只是把数据库的SQL写到VB中而已,那样就太小看Linq了。VB的目标是让一切包含数据的对象都可以用类SQL查询,包含数据库映射对象(DLinq),XML(XLinq),甚至是.NET Framework中的一切集合对象。

我们来看一个例子。假如Employee类有FirstName,LastName和Age等属性。现在有一个List(Of Employee)类型的集合叫做emp。假设我们要查询所有Age大于25的员工的姓名。回忆一下前面我们介绍的特性怎么给查询带来新的变化。首先我们给IEnumerable增加扩展方法Where:

<Extension()> _ Public Function Where(Of T)([Me] As IEnumerable(Of T), predicate As Func(Of T, Boolean))_ As IEnumerable(Of T) Dim result As New Collection(Of T) For Each Dim item In [Me] If predicate(item) Then result.Add(item) Next Return result End Function

注意Func,这是.NET Framework将会增加的一组泛型委托之一,用于On-the-fly创建各种参数个数和类型的委托,而不必声明新的委托类型。这里Func用于表示一个断言。于是我们就把条件查询封装了。与此同时,我们还可以封装一个Select方法,用于数据类型转换,以此类推,还可以有OrderBy和GroupBy等等……这些就成为Linq的查询算符。

回忆一下,我们还有嵌套函数,于是可以按下列方法使用查询算符:

Function F(obj As Employee)As Boolean Return obj.Age > 25 End Function Dim result = emp.Where(AddressOf F)

这里稍显麻烦的就是,我们需要自己定义函数,这样进行复杂查询就会写得很累,即使可能会有Lambda表达式帮助,我们也希望寻求更容易理解的方法,那就是查询包含Query Comprehension。新引入的Select,Where等查询关键字可以帮你完成前面介绍的一整套内容:

Dim result = Select It From e In emp Where e.Age > 25
一个简单的类似SQL的语法就帮助你生成了匿名的嵌套函数和所有算符的调用。注意It的用法,Select It就表示选择所有字段。我们只需要Employee的名字,那么就可以这样写:
Dim result = Select e.FirstName, e.LastName From e In emp Where e.Age > 25

这样,Select语句就会把查询的结果转化成一个Tuple(匿名类型的实例),它仅包含你所需要的字段。慢慢你就会发现,查询包含的威力可以延伸到你所能接触到的一切数据。这种关系型的语法很快就会代替For Each的手工迭代工作。

我们知道VB9将在XML方面有卓越的改进,当XML literal、XML后期绑定与查询包含的语法结合在一起后,将体现出非凡的简洁和高效,这是C# 3.0等同期语言无法比拟的,我们介绍到XML特性后再继续介绍。

posted on 2005-09-21 09:42:00 by Ninputer  评论(5) 阅读(6191)

Visual Basic 9.0 前沿播报·静态篇(四)嵌套函数和Closure

为了支持Linq平台所支持的查询特性,VB9必须引入少量“函数式编程(FP)”的特性。本次所介绍的嵌套函数和Closue特性就是最重要的一个环节。在我们探讨为什么引入这样一些特性之前,先来看看这个特性是什么样的。
VB9允许在过程内部定义函数或子程序,如:
Public Sub MyProc() Sub Nested() 'Code here End Sub End Sub
首先能够想到的第一个用途就是,一个帮助函数(HelperFunction)可以仅供某个过程单独使用,在这个过程外部无法访问到这个过程定义的嵌套函数。这与Delphi的嵌套函数类似。注意,嵌套函数仅可以在定义之后的上下文中访问。下面这个特性就是嵌套函数与传统函数最大的不同:
Public Sub MyProc() Dim x As Integer Sub Nested(i As Integer) x = i End Sub 'Invoke subroutine Nested(20) Console.WriteLine(x); End Sub

嵌套函数可以访问到外部过程中的变量,这个特性叫做Closure。有了Closure,我们就可以生成规则可变化的函数,以便实现延迟计算,这就是FP一个基本功能。VB9的内嵌函数Closure可能是通过Tuple特性来实现的,不过目前还没有关于原理的进一步细节。VB9内嵌函数相对于C#的匿名函数,主要有两个优点:

1。无需委托即可调用,可反复调用。当需要委托时,可通过AddressOf获取。
2。可直接递归。(当然,高手可以用Y算子,后话了……)

Visual Basic还考虑增加匿名内嵌函数的表达方式,就是众所周知的Lambda表达式。但是目前还没有语法放出来,我就先不介绍了。

posted on 2005-09-19 09:27:00 by Ninputer  评论(15) 阅读(6244)

Visual Basic 9.0 前沿播报·静态篇(三)扩展方法

Visual Basic 9.0支持新一代语言集成的查询功能,支持在DLinq的数据对象或者XLinq的XML数据上实施关系型的查询,这些查询是利用DLinq或者XLinq相关对象上一组方法(或者叫算符)来实现的。而VB9的开发人员认为这套查询方法也应该能用于现有的对象数据组织方式,比如IEnumerable和其他集合。因此,Visual Basic 9.0需要一种从外部给现有类型增加方法的功能,这就是扩展方法

扩展方法其实是一种编译器后台翻译的方法,原本是接受T类型参数的方法,可以用T类型成员的语法写出。这个语法仅用于类库设计者使用,不宜乱用,所以Visual Basic 9.0不提供特别的语法支持,类库设计者只需要把相应的Attribute置于声明扩展方法的模块与方法上即可。

<Extension()>Module MyExtension <Extension()> _ Public Function Count(Of T)([Me] As IEnumerable(Of T))As Integer For Each Dim item In [Me] Count += 1 Next End Function End Module

注意,我们把扩展方法的第一个参数命名为Me,是为了提醒程序员,这个参数在扩展方法起作用之后,就如同实例方法Me一样,当然这不是必须的,只是一种推荐做法。

扩展方法要起作用,并不是没有条件的,如果谁都扩展Framework中的方法,就会乱成一锅粥了。因此规定,需要用Imports语句导入扩展方法所在的模块,才能让扩展方法起作用。

Imports MyExtionsion

导入扩展方法之后,就可以使用该扩展方法了:

Dim arr = {1, 2, 3, 4, 5} Dim length = arr.Count '以上一句会被自动翻译成 'Dim length = MyExtionsion.Count(arr)

最后提醒一句,扩展方法只是语法糖,没有必要的扩展最好不要使用它。过多的扩展会导致语法清晰,但设计上糟糕的情况出现。请仔细考虑使用这个特性。

posted on 2005-09-16 09:14:00 by Ninputer  评论(3) 阅读(5593)

Visual Basic 9.0 前沿播报·静态篇(二)对象初始化器和匿名类型

在Visual Basic 2005以前的版本,如果类或结构没有定义初始化构造函数,我们就必须用属性逐一赋值的方式。比如

'假设有个结构Person,有Name和Age属性 'VB 2005代码 Dim p As Person With p .Name = "Jack" .Age = 27 End With

这样,对象的初始化不能与对象的定义同时完成,多少有些不便。特别是我们在表达式中需要Person类型的时候,无法就地生成,必须另写代码初始化,这会打断我们的思路。Visual Basic 9.0为所有对象提供了一个表达式初始化语法,让你可以对任何公有属性在初始化时一并赋值。(其实我早就想要这个语法了,呵呵)

Dim p = New Person{.Name = "Jack", .Age = 27}

看这个语法比以前简洁多了,就好像把With语句写在了初始化语句里一样。初始化语法并没有取代构造函数,而且它还可以和构造函数任何混合使用。比如假设Person类型有一个初始化Name的构造函数,你便可以这样写。

Dim p = New Person("Jack") {.Age = 27}

也就是说,初始化器并非要求对所有属性进行初始化。对系统里的List(Of T)类型,VB9还专门实现了List初始化语法:

Dim l1 = New List(Of Integer){1, 2, 3, 4} Dim l2 = New List(Of Person){ _ New Person{.Name = "Jack", .Age = 27}, _ New Person{.Name = "Lucy", .Age = 26}}

这种特性着实给我们编写代码带来了很大的方便,也让“表达式”所能表达的内容大大丰富了。“一句话编程”正在慢慢引入VB,呵呵。

最后我们介绍一下匿名类型。当你恰好需要一个结构变量有A As String, B As Integer两个成员,但事先没有定义。在VB2005中,你只能去定义它,而在VB9中,你可以将它当作一个Tuple

Dim item = New {.A = "xyz", .B = 123}

这一句,VB会为你创造出一个类型,就有两个字段A和B,分别是String和Integer类型,而item就直接成为“那个类型”的实例。匿名类型如前所述,最主要的用途是当成Tuple,可以用来保存查询的临时结果。这时候,局部变量类型推测的好处就体现出来了。注意,按照目前的设计,这一切过程都是在编译时完成的,匿名类型会变成实际类型保存在你的项目中,因此这一操作代价较大。所以Visual Basic组可能还在讨论使用CLR新特性做动态Tuple,让我们继续期待吧。

posted on 2005-09-15 09:54:00 by Ninputer  评论(6) 阅读(5957)

Visual Basic 9.0 前沿播报·静态篇(一)局部变量类型推测和数组初始化器

不要惊讶,每个PDC上都会有微软最新产品的前瞻,所以在Visual Basic 2005发布以前看到Visual Basic 9.0的消息就是可以理解的了。Visual Basic 9.0 (codename Visual Basic Orcas)将随下一个Visual Stduio主版本(9.0,Orcas)一起发布,但是微软很早就开始了新语言特性的规划,在今天(PST 9月13日)召开的PDC大会上,用户不仅可以领略到新一代Visual Basic 9.0的特性,还可以在动手实验室里亲自尝试预览版。没有参加PDC大会的VB Fans和开发者,可以从我的Blog获取首轮中文播报。注意现在距离VB9.0正式推出还很远,本系列文章仅对当前公布的内容做简单介绍,并不保证和正式版特性一致。

言归正传,这次Visual Basic 9.0的主题就是数据动态。VB9试图从语言角度上增强以获得前所未有的数据(包括对象中的数据、数据库和XML)开发体验。其次,Visual Basic试图从动态语言中吸取一些优良的特性,让用户感到更少受限制,更方便。此外还有一些和数据无关的静态特性。我打算将本文分成动态篇和静态篇,分别介绍Visual Basic 9.0近乎于两个世界的开发体验。

我要介绍的Visual Basic 9.0第一个新特性是局部变量类型推测。在以前版本,我们声明变量的同时,必须用As语句指定变量的类型。

Dim aInt As Integer = 5 Dim aDbl As Double = 3.33 Dim aStr As String = "Hello" Dim aLst As List(Of Integer) = anotherList.ConvertAll(Of Integer)(PStr.Length) 'VBF语法

我们观察这几个声明,他们的初始化语句都包含了足够确定返回类型的信息,比如“5”就已经确定为Integer。因此,在Visual Basic 9.0中,可以免除局部变量的类型声明,由初始化语句确定

Dim aInt = 5 Dim aDbl = 3.33 Dim aStr = "Hello" Dim aLst = anotherList.ConvertAll(Of Integer)(PStr.Length)

这样,变量的声明就被充分简化了。注意,这些代码似乎在Visual Basic 2005也有效,那么有什么不同呢?这里类型推测发生在编译时,是一种强类型特性。比如将aInt初始化为5,那么aInt并非是定义为Object类型,而是定义为真正的Integer,如果再给aInt赋值无法转换成Integer的数值,就会发生编译错误。在Visual Basic 2005中,Option Strict Off的情况下,不用As语句指定类型会默认为Object类型,这条规则到了Visual Basic 9.0将不再有效,要声明为Object类型必须显式指定As Object。注意最后一个,我们看到泛型类型的类型实参也会随类型推测一并确定,因此不再需要书写前思考返回类型的类型实参具体是什么了。

Visual Basic 9.0还支持For Each循环的循环变量类型自动推测。

Dim list As List(Of ALongNameStructure) = ... For Each Dim item In list '无需写As ALongNameStructure '使用list Next

注意Dim语句在此帮助推测了list中的成员类型,因此你就无需手工指定它了。

为了让类型推测对数组也起作用,VB9还引入了全新简化的数组字面量,现在数组可以通过初始化自动推测自己的类型。

'VB2005 数组定义和初始化都需要指定类型 Dim aIntArr As Integer() = New Integer() {1, 2, 3} 'VB 9.0 一切都自动推测 Dim aIntArr = {1, 2, 3} '写个括号也可以 Dim strArr() = {"a", "bb", "ccc"} '数组的数组也可以 Dim aIntArrArr = {{1, 2}, {3, 4}} '注意类型不统一会推测成基类,下面例子成了Object数组 Dim objArr = {1, "2", 3.1}
类型自动推测有一个限制,它只能对局部(非Static)变量进行推测,不支持对类层次的变量进行推测,即使有初始化语句也不行。

作为VB9数据新特性的基础,局部变量类型推测是一个很重要的特性,但初看其来很简单,似乎没有必要。因此你只先要记住它,当看到我后续文章的时候,你自会了解它的用处。敬请期待下一篇:对象初始化器和匿名类型。

posted on 2005-09-14 08:47:00 by Ninputer  评论(8) 阅读(8614)

Powered by: Joycode.MVC引擎 0.5.2.0