【IT168 技术文档】
匿名类型
经常我们想从一个查询结果中移开或者取出一些类型的成员。比如说我们想取处热带国家的Name和Country,使用经纬度来指定热带区域,并且在结果中突出这些值。在VB9中,我们通过创建一个对象实例--无须对类型进行命名--对每个处于南北回归线中间的城市C:
Const TropicOfCancer = 23.5
Const TropicOfCapricorn = -23.5
Dim Tropical = Select New{ .Name = City.Name, .Country = City.Country } _
From City In Capitals _
Where TropicOfCancer =< City.Latitude _
AndAlso City.Latitude >= TropicOfCapricorn
本地变量Tropical的推断类型是一个匿名类型的实例的集合,也就是IEnumerable(Of { Name As String, Country As String })。Visual Basic编译器将会创建一个新的,系统生成的类,如_Name_As_String_Country_As_String_,它的成员名和类型都是通过对象初始化推断出来的:
Class _Name_As_String_Country_As_String_
Public Property Name As String
Public Property Country As String
Public Default Property Item(Index As Integer) As Object
...
End Class
在同一个程序里,编译器将会合并相同的匿名类型。两个指定了相同名称和类型的属性顺序的匿名对象初始化将会产生相同的匿名类型实例。形式上看,VB产生的匿名类型被转化为Object,这样允许编译器一致的将匿名类型作为参数或者函数结果传递。在VB代码里,编译器会对产生的类使用特别定制的属性进行标识,以提示类型_Name_As_String_Country_As_String_实际代表了匿名类型{ Name As String, Country As String }。
因为匿名类型一般都是用来把一个已有类型中的成员提取出来,VB9.0允许使用简单的表示方法New { City.Name, City.Country }来简写长语法的New { .Name = City.Name, .Country = City.Country }。当在一个查询综合的结果表达式中使用时,我们可以进一步简化:
Dim Tropical = Select City.Name, City.Country _
From City In Capitals _
Where TropicOfCancer =< City.Latitude _
AndAlso City.Latitude >= TropicOfCapricorn
注意长表达和短表达的效果都是一样的。
深层次的XML支持
XLinq是一个新的,常驻内存的XML编程API,它主要是为了提升最新的.net框架的语言集成的查询框架能力而设计的。就像查询综合给标准的.NET框架查询操作增加了熟悉的方便的语法一样,Visual Basic 9.0通过XML literals和late binding over XML提供了对XLinq的支持。
为了探究XML,我们同对对平面关系数据源Countries和Capitals的查询,构造一个层次的XML模型,把每个城市的首都作为一个子元素,并且计算人口密度作为属性。
为了查找给定国家的首都,我们对每个国家的name成员和每个城市的国家名进行join操作。给定一个国家和它的首都,我们可以通过使用已经计算的值填充嵌套的表达hole轻松的构建XML段。我们可以用括号括起name属性来写"hole",如Name=(Country.Name),也可以从ASP.NET中借来一种特殊的方式,如<Name><%= City.Name %></Name>。这里是我们结合XML和查询综合的查询:
Dim CountriesWithCapital As XElement = _
<Countries> <%= Select <Country Name=(Country.Name)
Density=(Country.Population/Country.Area)>
<Capital>
<Name><%= City.Name %></Name>
<Longitude><%= City.Longitude %></Longtitude>
<Latitude><%= City.Latitude %></Latitude>
</Capital>
</Country> _
From Country In Countries, City In Capitals _
Where Country.Name = City.Country %>
</Countries>
注意XElement类型可以从声明中省略,在这里它将像其他本地声明一样进行推断。我们在这里也留下了一个显式类型,下面将解释。
在这个声明里,我们希望在<Countries>元素里Select查询的结果进行替代。因此,Select查询是第一个hole的内容,在<Countries>里使用熟悉的ASP.NET形式的标志<%=and%>来分割。因为Select查询结果是一个表达式,XML literal也是表达式,自然,Select内也可以嵌套使用Select。这样的嵌套式的使用包含了嵌套的"hole"Country.Name和计算的人口密度率Country.Population/Country.Area,还有首都的名字和坐标。
当编译运行时,上面的查询将会返回如下的XML文档:
<Countries>
<Country Name="Palau" Density="0.037117903930131008">
<Capital>
<Name>Koror</Name>
<Longitude>135</Longitude>
<Latitude>8</Latitude>
</Capital>
</Country>
<Country Name="Monaco" Density="16694.21052631579">
<Capital>
<Name>Monaco</Name>
<Longitude>7.2</Longitude>
<Latitude>3.7</Latitude>
</Capital>
</Country>
<Country Name="Belize" Density="9.5512195121951216">
<Capital>
<Name>Belmopan</Name>
<Longitude>-88.5</Longitude>
<Latitude>17.1</Latitude>
</Capital>
</Country>
<Country Name="Madagascar" Density="23.287181452711909">
<Capital>
<Name>Antananarivo</Name>
<Longitude>47.4</Longitude>
<Latitude>-18.6</Latitude>
</Capital>
</Country>
</Countries>
Visual Basic 9.0编译XML literal成System.Xml.XLinq对象,保证其他使用XLinq的语言和VB一样具有互操作性。在我们这个例子里,编译器产生的代码(如果我们可以看到的话)可能是:
Dim CountriesWithCapital As XElement = _
New XElement("Countries", _
Select New XElement("Country", _
New XAttribute("Name", Country.Name), _
New XAttribute("Density", Country.Population/Country.Area), _
New XElement("Capital", _
New XElement("Name", City.Name), _
New XElement("Longitude", City.Longitude), _
New XElement("Latitude", City.Latitude)
)
)
From Country In Countries, City In Capitals _
Where Country.Name = City.Country)