Visual Basic 2008中的隐藏特性

[原文作者]Amanda Silver

[原文链接]Hidden Gems in Visual Basic 2008

 

昨天我答应写一些大家在以前的博客中没有看到的关于Visual BasicVisual Studio 2008的新东西,我把它叫做隐藏宝石。我曾提到过在VS2008中的一些特性我很喜欢,还炫耀过智能感知(Intellisense )的改善,尤其是对关键字、本地变量和表达式,自动完成语句的改进。在过去,我还提到过一个新的语法特性,称之为Relaxed Delegates,它允许你为事件(event)提供一个可替代的签名(alternate signatures)。以上这些都是很好的特性,但我今天要说的不是这些,是隐藏宝石(可能这些你在一些C#的文章中见过了,Visual Basic 2008中一样炫)

 

     我挑选出了10个最重要的特性,只是简单的介绍一下,有兴趣的可以继续深入研究。

     首先,从一个基调特性(keynote feature)开始。

 

0)多个target Framework支持(Multi-targetting

简单的说,Multi-targetting支持你在VS2008VB9下用.NET 2.0 framework进行编译。下面我将要讲到的所有特性都在.NET 2.0下有效,所以当你打开Visual Studio创建一个project以后,把framework target设置为2.0(除了第5和第7项,因为它们需要LINQObjectsXML APILINQ是在.NET 3.5才推出)。如图:

 

1)   输入推断(Type Inference

Visual Basic 9里面,下面的这一小段代码以及Nothing都是延迟绑定(late-bound)——在编译时(compile tine)一切都是延迟绑定,这就意味着你可以得到智能感知和输入推断。

Dim dialog = New OpenFileDialog()

        Dim result = dialog.ShowDialog()

        Dim printStr = “C:\”

        If result = Windows.Forms.DialogResult.OK Then

            printStr = dialog.FileName

        End If

        MsgBox(printStr)

这使得在输入代码时更加快捷,简单和准确。

 

2)   IF操作符

还记得吗,IIF函数能返回一个对象(Object),这意味着你不需要通过智能感知或类型推断就可以得到默认的返回值(Object类型)。如果你坚持要类型安全或代码前绑定,可以强制转换,代码如下:

Dim intC As Integer = CInt(IIf(intA = intB, intA, intB – 1))

现在用IF操作符,你可以这么写:

Dim intD As Integer = If(intA = intB, intA, intB)

如果加上类型推断,代码就更简单了:

 

3)   对象初始化(Object Initializers

总的来说,在.net framework里,对象初始化是一种类似于把Dimstatement combined整合在一起的表达式。这样使得参数构造器多少让人容易接受一些:

Dim strm As New StreamWriter( _

                  New FileStream(“C:\out.txt”,FileMode.OpenOrCreate) _

                        With {.Position = 10})

对象初始化使得创建一个数组对象更加容易:

Dim Capitals() As City = {New City With {.Name = “Antanarivo”, .Country = “Madagascar”}, _

New City With {.Name = “Belmopan”, .Country = “Belize”}, _

New City With {.Name = “Monaco”, .Country = “Monaco”}, _

New City With {.Country = “Palau”, .Name = “Koror”}}

 

4)  Nullable

Nullable 是一种特性,可能你知道但没有关注过。它是一个基本的.NET 表达式,专门针对nullable类型,主要用于LINQNullable支持你写一段代码,其中的属性以null值传播。例如下面这点代码,在Country type中有个independence property nullable date

Dim virginIslands As New Country With {.Independence = Nothing}

        Dim palau As New Country With {.Independence = #10/1/1994#}

 

        Dim vILength = #8/24/2005# – virginIslands.Independence ‘ Nothing

        Dim pLength = #8/24/2005# – palau.Independence ‘ 3980.00:00:00

 

5)  LINQ to DataSet

它意味着你可以不用调用其他数据访问技术就能收获LINQ的好处。先填充一个DataSet,然后就可以对这个DataSet进行查询。

Me.EmployeesTableAdapter.Fill(Me.NORTHWNDDataSet.Employees)

        Dim query = From emp In Me.NORTHWNDDataSet.Employees _

                    Where emp.Country = “USA” _

                    Order By emp.HireDate _

                    Select emp

        Me.EmployeesBindingSource.DataSource = query

 

6)  语法提示(Syntax Tooltips

看看这个是不是很cool

再看看这个

还有这个

7)  namespace被用在XML 文档中时,智能感知会对namespace前缀和local name进行匹配,你只要为输入带来很大便捷,你只要输入开头几个字母然后回车,VS会帮你找到匹配的字段并加上相应的前后缀。下面是个小例子,以一个输入文件开始,然后使用智能感知。

此时我们只输入字母tVS会自动选中tomato

 

8)   GoTo Type Definition

通常,当你定义了一个变量,你想通过Object Browser浏览它在代码中的类型定义的时候,现在你多了一种选择,通过context menu可以让你直接找到它的定义。这点非常好,尤其是涉及到类型推断时能帮你确定该变量的类型是否和你想象的一致。

 

9)   循环变量的输入推断(Type inference for loop variables

检查下面这段代码:

还有这段

如果没有指定控制变量的类型,它会根据表达式或循环的信息从右往左推断。

 

10)   性能的提高以及非封闭性操作

后台编译器有一个非常强大的特性,它可以给你及时地反馈只要你写的代码正确。在这个版本的Visual Studio中我们对后台编译器做了很大的改进,我们相信后台编译器比以前快3倍但只用原先1/3的内存。任何使用过VS2008的人都会意识到这一点。虽然我们在性能上做了很大的改进,但是在大项目里面某些操作符仍然是一个巨大的花费,例如改变一个base classdeclaration         通常会被多次用到。如果在后台编译器工作之前,你试图调用一些依赖于编译信息的特性(例如IntellisenseDrop Downs),在以前版本的VS中会有一个长时间的停顿直到编译完成为止,但是现在这个问题解决了,当你想得到drop downs的时候就像这样:

VS很快会有响应。

 

从SQL 到 LINQ, Part 2: FROM 和 SELECT(Bill Horst)

[原文作者]: Bill Horst

[原文链接]: Converting SQL to LINQ, Part 2: FROM and SELECT (Bill Horst)

 

在看这篇文章之前,我假定你已经读过了SQLLINQPart 1:基础

 

为了让代码示例更清晰,我修改了下列名字:

·         Customers -> CustomerTable

·         Orders -> OrderTable

·         cust -> Contact

·         CustomerName -> ContactName

·         ID -> ContactID

 

欢迎你们的任何反馈和建议,你们的意见可以使以后的文章更清晰更有用。

 

好,现在开始讨论具体的子句(clauses),我们将从最基础的FROMSELECT开始。

 

FROM

 

SQLSELECT语句由SELECT子句开始,并且紧跟着一个FROM子句。而VB查询表达式则由From子句(或者Aggregate子句,我们稍后讨论)开始。一个基本SQLFROM子句指定了一个要操作的表,一个LINQFrom子句指定了一个我们要操作的对象(CustomerTable)。这个对象可以表示“已在内存中的”(“In-Memory”)数据:比如一个SQL表,或者XML信息。因为使用这样的数据比较简单,我的例子也采用了”In-Memory”的数据。除了这个数据对象,VBFrom子句还包含了一个指定当前“行”(Contact)别名的标识符。

 

如果要选择所有的列,在SQL中我们需要使用”*”,而在VB中,我们不需要附加任何东西,From子句默认返回所有的内容。

 

SQL

SELECT *

FROM CustomerTable

 

 

VB

From Contact In CustomerTable

 

 

FROM里的别名(alias)

 

SQL允许你在FROM子句中指定一个表的别名,LINQ同样允许我们这样做。

 

SQL

SELECT Contact.CustomerID, Contact.Phone

FROM CustomerTable Contact

 

 

VB

From Contact In CustomerTable

Select Contact.CustomerID, Contact.Phone

 

 

SELECT

 

SQLSELECT语句由一个包含要select的内容的列表开始(Name, CustomerID) 类似的,LINQ也允许你指定要select的内容,并将结果包装成一个匿名类型(anonymous type)返回。你指定的内容并不一定要是From子句指定对象的一部分,你可以指定任意合法的VB表达式(比如34)。如果成员的名字不能够被推断,你必须为其指定一个别名(见下面的“SELECT里的别名”)。

 

SQL

SELECT Name, CustomerID

FROM CustomerTable

 

 

VB

From Contact In CustomerTable

Select Contact.Name, Contact.CustomerID

 

 

SELECT里的别名

 

SQL允许SELCT子句的成员有别名(ContactName, ContactID),我们可以在查询语句的其它子句中使用这些别名。LINQ也允许别名,并且你可以在所有使用这个查询结果的代码中使用它们。

 

SQL

SELECT Name ContactName, CustomerID ContactID

FROM CustomerTable

 

 

VB

From Contact In CustomerTable

Select ContactName = Contact.Name, ContactID = Contact.CustomerID

 

 

下次我打算讲到DISTINCT, WHERE, ORDER BY 和运算符。

– Bill Horst, VB IDE Test

LINQ 菜谱, 菜单2: 查找短语中所有大写字母开头的单词并按长度排序 (然后是按字母顺序) (Kit George)

[原文作者]Kit George

[原文链接]LINQ Cookbook, Recipe 2: Find all capitalized words in a phrase and sort by length (then alphabetically) (Kit George)

 

准备材料:

–         Visual Studio 2008 (Beta2 或更高版本)

–         一些需要搜索的字符串

 

类别:  LINQ-To-Objects, LINQ and string, LINQ and WinForms

 

制作方法:

–         打开Visual Studio 2008,点击菜单文件/新建项目”,找到并双击 ”Windows 窗体应用程序图标

        拖放一个Listbox 到窗体上,调整的高度,然后拖放一个按钮到窗体上

–         双击这个按钮,并将下面的代码添加到按钮的事件处理函数中:

 

        Dim text = “Good morning everyone. I’d like to welcome “ & _

                   “you to today’s presentation on LINQ. My “ & _

                   “name is Kit George and I’m a Program Manager “ & _

                   “for Microsoft, on the Visual Basic team. You “ & _

                   “might be wondering where my accent is from? “ & _

                   “Well, I hail from a small country called New “ & _

                   “Zealand but it sure is great to be here in  “ & _

                   “Atlanta today!”

 

        Dim capitalWords = _

                      From word In text.Split( _

                      New Char() {“,”, “.”, “!”, ” “}, _

                      StringSplitOptions.RemoveEmptyEntries) _

                      Where word(0) = Char.ToUpper(word(0)) _

                      Order By word.Length, word

 

        ListBox1.Items.AddRange(capitalWords.ToArray())

 

–   修改你要搜索的字符串。如果字符串保存在一个文件中,  可以使用 My.Computer.FileSystem.ReadAllText 获取并保存到字符串变量中。

Visual Studio – 创建Add-In 工程

[原文作者]: Beth Massi

[原文链接]:  Visual Studio Tip of the Day – Let’s Build an Add-In

我已经开始使用Visual Studio 创建一些Add-In的工程, 这的确是一个比较容易的过程. 真正值得高兴的是,我们不需要去单独安装SDK 去创建Add-in工程,这已经集成在Visual Studio. 我之前写过一个从Sararss feed浏览他的文章的程序.现在我们看看怎么用Visual Studio 2008实现的. 你可以从这里下载代码.

首先我们添加一个新的工程到你的项目中, Add –> New Project, 展开 “Other Project Types”选择”Extensibility” 然后选择”Visual Studio Add-In”.

这会打开一个向导帮助你配置一些你的add-in程序.第一步是选择语言”Create an Add-in using Visual Basic”, 进行到下一步.

下一步选择add-in程序的宿主.在这个程序中我们选择 Visual Studio 2008 Macros”,因为我只想让这个程序起运并显示在工具菜单栏上.

再下一步是Add-in程序的名字和描述. 我们把名字和描述改成 Visual Studio Tip of the Day”.

下一步,向导会问我们怎么样去起运Add-in程序, 在这个程序中我们需要在Visual Studio打开的时候载入,并且提供一个在工具栏上的菜单.选择相应的选项,进行到下一步.

最后一步,向导会我们是否需要一个”About”,我们会跳过这一步, 结束向导.

一个新Add-in工程会被加入到你的项目中.  然后打开Add-in工程的属性页,选择”Compile”, 进入”Advanced Compile Options…”,Target Framework改成 .NET Framework 3.5

我们需要添加引用到我们上文提到的(SaraRssViewer) 工程, 现在我们已经有了引用并且配置好了target framework,打开Connect.vb 文件,” OnStartUpComplete”方法中我们会加入代码去载入窗体.

Public Sub OnStartupComplete(ByRef custom As Array) _

  Implements IDTExtensibility2.OnStartupComplete

 

    Dim frm As New SaraRSSViewer.Form1

    frm.Show()

End Sub

当你从工具菜单选择我们的Add-in的时候, 这个程序会被运行, 我们需要把同样的代码加入Exec方法.

Public Sub Exec(ByVal commandName As String, _

                ByVal executeOption As vsCommandExecOption, _

                ByRef varIn As Object, ByRef varOut As Object, _

                ByRef handled As Boolean) _

           Implements IDTCommandTarget.Exec

 

    handled = False

    If executeOption = vsCommandExecOption.vsCommandExecOptionDoDefault Then

        If commandName = “MyAddin1.Connect.MyAddin1” Then

 

            Dim frm As New SaraRSSViewer.Form1

            frm.Show()

 

            handled = True

            Exit Sub

        End If

    End If

End Sub

 

然后我们按F5运行我们的程序, 这样你就可以看到我们的Add-in程序运行的效果,

你也可以自己定制你的菜单名,OnConnection方法中,定义Command变量,第三个参数是显示菜单名,第四个是改变tolltip.

Dim command As Command = _

    commands.AddNamedCommand2(_addInInstance, _

                              “MyAddin1”, _

                              “Tip of the Day”, _

                              “Display the Visual Studio tips of the day”, _

                              True, 59, Nothing, _

                              CType(vsCommandStatus.vsCommandStatusSupported, Integer) + _

                              CType(vsCommandStatus.vsCommandStatusEnabled, Integer), _

                              vsCommandStyle.vsCommandStylePictAndText, _

                              vsCommandControlType.vsCommandControlTypeButton)

当我们编译Add-in工程的时候,会把.addin 文件添加到Visual Studio 2008\Addins\文件夹下面. 通过这个例子,我们可以看创建一个Add-in程序的确很简单.你也可以一些尝试其他的例子,比如OfficeAdd-in等等.

在以后的文章中,我会写一些关于如何把Add-in程序部属到其他机器的方法.

 

从SQL 到 LINQ, Part 1: 基础(Bill Horst)

[原文作者]: Bill Horst

[原文链接]: Converting SQL to LINQ, Part 1: The Basics

你可能已经知道了,VBLINQ指令允许使用类SQL语法的查询。LINQ的语法并不和SQL的语法完全一致,所以如果你现在已经在用SQL或者熟悉SQL查询的话,你可能会想把已经存在的SQL查询转化为LINQ

这篇文章就是“从SQLLINQ”系列的第一篇。在这篇文章里,我想让大家对SQLLINQ的区别有一个基本的理解,下次我们会涉及到具体的语言架构。

 

假定

 

在接下来的例子, SQL代码会涉及到两个tableCustomersOrdersVB代码会用到与之同名的两个对象,他们的类型分别是IEnumerable(Of Customer)IEnumerable(Of Order)。我还会用到两个类,同样是CustomerOrder,如下:

Class Customer

    Public CustomerID As Integer

    Public Name As String

    Public Phone As String

    Public Address As String

    Public City As String

    Public State As String

    Public Zip As String

End Class

 

Class Order

    Public OrderID As Integer

    Public CustomerID As Integer

    Public Cost As Single

    Public Phone As String

    Public OrderDate As DateTime

    Public ShippingZip As String

    Public ItemName As String

End Class

 

基本语法

 

LINQ支持SQL SELECT语句,而不支持其他的,比如CREATE, INSERT, UPDATE DELETE。你可以认为SQL SELECT语句的基本语法是一系列的“子句”(clauses),其中的第一个是SELECT子句。

sqlSelectClause [ sqlClause1 [ sqlClause2 [ … ] ] ]

 

SQL的语法可能根据不同的版本有所差异,下面是一个例子:

SQL

SELECT Name CustomerName, CustomerID ID

FROM Customers

ORDER BY ID

 

VB LINQ表达式的基本语法也是一系列的子句,不同的是第一个是From子句(或者Aggregate子句,我们稍后会讨论)。

linqFromClause [ linqClause1 [ linqClause2 [ … ] ] ]

 

比如:

VB

From cust In Customers _

Select CustomerName = cust.Name, ID = cust.CustomerID _

Order By ID

 

我刚才用了“VB LINQ表达式”的说法是因为前面的“LINQ查询”不是一个完整的语句。虽然SQL语句可以单独出现,但是LINQ查询在语法上和表达式“3 * 4”一样 - 它不是一个完整的语句,所以我们要使它完整。一个VB的完整的LINQ查询的语句看起来像这样:

VB

Dim SortedCustomers = From cust In Customers _

                      Select CustomerName = cust.Name, ID = cust.CustomerID _

                      Order By ID

 

从概念上说,LINQ查询的每个子句操作的都是IEnumerable(Of T)类型并且返回的也是IEnumerable(Of T)类型”(其中的两个T并不一定要相同)。查询子句和SQL子句是基本类似的(比如SELECT, ORDER BY),所以你可以一个子句一个子句地将SQL查询转化成LINQ。在上面的例子里,这些子句出现的顺序稍有不同,而且有些语法上的差异,但是你可以看到,他们非常类似。

还要注意的一点是,SQL语法允许在子句间直接换行,而在VB里,换行需要在每行最后加上下划线(_)去告诉编译器下一行仍然是当前的表达式。

这篇文章只是一个泛泛的说明,但我会在以后讲到更为具体的内容。我打算涉及以下条目:

  • FROM and SELECT
  • DISTINCT, WHERE, ORDER BY, Operators
  • Functions (Scalar and Aggregate)
  • GROUP By and HAVING
  • Joins
  • UNION, TOP and Subqueries

– Bill Horst, VB IDE Test