VB.NET的隐藏功能是什么?

121
我浏览了C#的隐藏功能,学到了不少知识,但惊讶的是我找不到类似于VB.NET的内容。
那么,它有哪些隐藏的或较少人知道的功能呢?
64个回答

128
Exception When从句很少被使用。
考虑以下内容:
Public Sub Login(host as string, user as String, password as string, _
                            Optional bRetry as Boolean = False)
Try
   ssh.Connect(host, user, password)
Catch ex as TimeoutException When Not bRetry
   ''//Try again, but only once.
   Login(host, user, password, True)
Catch ex as TimeoutException
   ''//Log exception
End Try
End Sub

9
如果您希望捕获特定的SQLException,比如说-2,如果我没记错的话,它表示网络超时,那么以下代码可能会有所帮助: 使用以下代码捕获code属性为-2的sqlException异常: Catch ex as sqlException where(ex.code = -2) - Pondidum
哇!我刚刚读了这个并立即将其用于简化我上周编写的 try/catch 块。我从来不知道这存在。 - John M Gant
1
+1 这里是.NET CLR团队博客解释异常过滤器为什么有用的地方 http://blogs.msdn.com/clrteam/archive/2009/02/05/catch-rethrow-and-filters-why-you-should-care.aspx - MarkJ
5
不仅这是隐藏的,而且在C#中也不可用。 - Cheeso

82

自定义 Enum

VB 中一个真正的隐藏功能是 completionlist XML 文档标签,可以用它创建具有扩展功能的自定义 Enum-like 类型。然而,在C#中该功能并不起作用。

以下是我最近代码中的一个示例:

'
''' <completionlist cref="RuleTemplates"/>
Public Class Rule
    Private ReadOnly m_Expression As String
    Private ReadOnly m_Options As RegexOptions

    Public Sub New(ByVal expression As String)
        Me.New(expression, RegexOptions.None)
    End Sub

    Public Sub New(ByVal expression As String, ByVal options As RegexOptions)
        m_Expression = expression
        m_options = options
    End Sub

    Public ReadOnly Property Expression() As String
        Get
            Return m_Expression
        End Get
    End Property

    Public ReadOnly Property Options() As RegexOptions
        Get
            Return m_Options
        End Get
    End Property
End Class

Public NotInheritable Class RuleTemplates
    Public Shared ReadOnly Whitespace As New Rule("\s+")
    Public Shared ReadOnly Identifier As New Rule("\w+")
    Public Shared ReadOnly [String] As New Rule("""([^""]|"""")*""")
End Class
现在,当给一个声明为Rule的变量赋值时,IDE会提供智能感知列表,列出可能的值来自于RuleTemplates

/EDIT:

由于这是一个依赖于IDE的功能,很难展示它的使用方式,但我可以使用一张屏幕截图:

Completion list in action http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png

实际上,这个智能感知与使用Enum时所得到的完全相同。


有趣 - 你能展示一下当你使用它时的例子吗? - Brian MacKay
看起来有人仍然可以通过直接调用规则构造函数来创建自己的规则?如果是这样,并且您想要阻止这种情况,您可以在库中将构造函数声明为“Friend”吗? - Joel Coehoorn
Joel,在我的示例代码中,我有意没有禁止这种情况。相反,我提供了一些常见规则,并允许创建自己的专业规则。当然,您可以通过将构造函数标记为“friend”或使用与枚举相同的类“Rule”而不是“RuleTemplate”来防止这种情况。 - Konrad Rudolph
你也可以将一个类作为自己的完成列表。 - Instance Hunter
当与策略模式结合使用时,这绝对是一个不错的奖励(正如您的示例所示)。 - STW
显示剩余3条评论

49

你有没有注意到 Like 比较运算符?

Dim b As Boolean = "file.txt" Like "*.txt"

更多信息请参考MSDN

Dim testCheck As Boolean

' The following statement returns True (does "F" satisfy "F"?)'
testCheck = "F" Like "F"

' The following statement returns False for Option Compare Binary'
'    and True for Option Compare Text (does "F" satisfy "f"?)'
testCheck = "F" Like "f"

' The following statement returns False (does "F" satisfy "FFF"?)'
testCheck = "F" Like "FFF"

' The following statement returns True (does "aBBBa" have an "a" at the'
'    beginning, an "a" at the end, and any number of characters in '
'    between?)'
testCheck = "aBBBa" Like "a*a"

' The following statement returns True (does "F" occur in the set of'
'    characters from "A" through "Z"?)'
testCheck = "F" Like "[A-Z]"

' The following statement returns False (does "F" NOT occur in the '
'    set of characters from "A" through "Z"?)'
testCheck = "F" Like "[!A-Z]"

' The following statement returns True (does "a2a" begin and end with'
'    an "a" and have any single-digit number in between?)'
testCheck = "a2a" Like "a#a"

' The following statement returns True (does "aM5b" begin with an "a",'
'    followed by any character from the set "L" through "P", followed'
'    by any single-digit number, and end with any character NOT in'
'    the character set "c" through "e"?)'
testCheck = "aM5b" Like "a[L-P]#[!c-e]"

' The following statement returns True (does "BAT123khg" begin with a'
'    "B", followed by any single character, followed by a "T", and end'
'    with zero or more characters of any type?)'
testCheck = "BAT123khg" Like "B?T*"

' The following statement returns False (does "CAT123khg" begin with'
'    a "B", followed by any single character, followed by a "T", and'
'    end with zero or more characters of any type?)'
testCheck = "CAT123khg" Like "B?T*"

3
等等,什么?这对我来说是新的!嗯,这比使用VB.NET字符串操作要好得多了 :D - STW
@dotjoe 嗯?这些通配符并不“懒”。 - Josh Lee
这个程序执行得如何?在幕后发生了什么?它是正则表达式库的同义词吗? - brumScouse
不,它编译成一个简单的静态函数调用:Microsoft.VisualBasic.CompilerServices.LikeOperator.LikeString。对于一些人来说,这可能看起来像作弊,但当涉及到LINQ时,它变得非常有趣。 - Parsa
“Like”是我最喜欢的VB字符串工具。作为一个Perl和正则表达式迷,我非常欣赏它的功能。 - Br.Bill
显示剩余3条评论

48

类型定义

VB 通过 Import 别名提供了一种基本的 typedef 实现方式:

Imports S = System.String

Dim x As S = "Hello"

当与泛型类型一起使用时,这将更加有用:

Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)

2
我的集成开发环境无法识别Import这个关键字。 - Shimmy Weitzhandler
5
“Imports”应该是正确的。;-) 不知何故,这个错误在将近一年的时间里未被发现(并获得了28个赞)。 - Konrad Rudolph
我一直想知道如何为泛型创建一个带有默认值的新“类型”!太酷了! - eidylon
3
导入、导入、Importz,随便叫什么!唉,你认为我们在点赞之前会这些帖子吗! - MarkJ
在Visual Studio测试中使用xUnit非常出色,例如Imports Assert = xUnit.Assert - wheelibin

45

噢!别忘了XML字面量

Dim contact2 = _
        <contact>
          <name>Patrick Hines</name>
          <%= From p In phoneNumbers2 _
            Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
          %>
        </contact>

这正是我要说的。事实上,我曾经在一个不打算使用XML文本的地方使用了它。我用它来生成Javascript... http://swortham.blogspot.com/2009/03/vb-2008.html - Steve Wortham
9
除其他用途外,您可以使用 XML 文字来避免丑陋的字符串转义,例如在使用包含双引号的字符串时。只需将字符串放置在 XML 文字中并调用 Value,就像这样:<string>This string contains "quotes" and it's OK.</string>.Value (我发现在编写解析每个字段都带引号的 CSV 文件的测试时特别方便。手动转义所有这些引号将是非常麻烦的。) - Ryan Lundy
2
@Kyralessa:+1,非常好的评论。实际上,这也是指定多行字符串(拥抱SQL语句等)的好方法。 - Heinzi
内联 XML 是有史以来最糟糕的 VB.NET 功能之一。未经证实的事实。 - Grant Thomas

39

初始化对象也在其中!

Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}

1
我简直不敢相信他们选择了花括号。我们已经有了 With 语句...他们本可以重用那个语法。 - Sam Axe
2
我知道,这只是为了向你展示路上没有警察... 哈哈开玩笑。 - Shimmy Weitzhandler
4
当所有编译器的编写者本质上都是C/C++程序员时,就会出现这种情况。他们会在其他语言中不自觉地加入C语法,因为他们无法想象有更好的东西。 - RBarryYoung

38

DirectCast

DirectCast 是一个神器。表面上看,它类似于 CType 运算符,将一个对象从一种类型转换为另一种类型。但是,它遵循一组更严格的规则。 CType 的实际行为通常是不透明的,无法明确执行哪种类型的转换。

DirectCast 仅支持两个不同的操作:

  • 值类型的拆箱(unboxing)操作;
  • 在类继承层次结构中向上转型(upcasting)。

任何其他类型的转换都不起作用(例如尝试将 Integer 拆箱成 Double),并会导致编译时/运行时错误(具体取决于情况和静态类型检查所能检测到的问题)。因此,尽可能使用 DirectCast,因为这最能准确地表达我的意图:根据情况,我要么想拆箱已知类型的值,要么执行向上转型。就这样。

另一方面,使用 CType 会让代码的读者不确定程序员真正的意图,因为它会解析各种不同的操作,包括调用用户定义的代码。

为什么这是一个隐藏的特性?VB 团队发布了一份指南1,不鼓励使用 DirectCast(尽管实际上它更快!),以使代码更加统一化。我认为这是一个不好的指南,应该被扭转:无论如何,都应该优先选择 DirectCast 而不是更通用的 CType 运算符。它可以使代码更加清晰易懂。另一方面,只有在确实需要时,即当需要调用缩窄的 CType 运算符时(参见运算符重载),才应该调用 CType


1) 我无法提供指南的链接,但我找到了VB团队的首席开发人员Paul Vick的看法

在实际应用中,你几乎不会注意到其中的区别,因此最好选择更灵活的转换运算符,如CType,CInt等。


(Zack编辑:在这里了解更多: VB.NET中应该如何进行强制类型转换?


我其实更喜欢 TryCast()。如果转换失败,它不会抛出异常,而是返回 Nothing。如果你预计转换经常失败,那么它比 If TypeOf x Is T... 更快,肯定比捕获 DirectCast 失败的异常更快。 - Bob King
6
如果正确使用一对 DirectCast() 和 TryCast(),它们将非常有价值。当被转换的对象总是期望为目标类型时,应使用 DirectCast()(如果不是,您将得到一个错误,这是一个好事情,因为它是一个意外的情况)。如果被转换的对象可能是目标类型或多个目标类型之一,则应使用 TryCast()。只使用其中一个会导致额外的开销(如果 typeof x is y,则 directcast(x, y) 是低效的),或者避免有效的错误(在对象应始终为目标类型的情况下使用 TryCast())。 - STW
Yoooder:100%正确。遗憾的是我当时没有提到TryCast,因为我主要对普遍使用的CType有意见。 - Konrad Rudolph
@Maslow:当然不行,因为枚举是值类型,而根据文档,TryCast 仅适用于引用类型。 - Konrad Rudolph
+1:嘿。我得承认,我刚刚读到这个,想到了“哦,是的,DirectCast,我怎么会忘了呢?”然后我在我的下一行代码中使用了它(因为我真的不喜欢CType)。 - RBarryYoung

37

If条件语句和合并运算符

我不知道你会不会把它叫做隐藏的,但是 Iif([expression], [value if true], [value if false]) 函数可以算作一个。

它不是很隐藏,而是已弃用!VB 9有了更好的 If 运算符,它的功能类似于 C# 的条件运算符和合并运算符(取决于你想要什么):

Dim x = If(a = b, c, d)

Dim hello As String = Nothing
Dim y = If(hello, "World")

编辑以展示另一个例子:

这将适用于If(),但会导致IIf()抛出异常。


Dim x = If(b<>0,a/b,0)

好知道。不过,如果你的工作需要针对2.0框架进行开发,它并不完全被弃用。 - Sam Erwin
4
告诉Visual Studio 2005。并不是所有人都能使用最新的和最棒的工具。 - Sam Erwin
3
@ Slough,无稽之谈。这种方法是百分之百类型安全的,并且返回与其(第二个和第三个)参数相同类型的对象。此外,参数之间必须存在宽化转换,否则将出现编译错误,因为类型不匹配。 - Konrad Rudolph
1
是的,它的IIf()不是类型安全的。 - Pondidum
2
@Br.Bill 实际上,它与 C 和 Perl 的 :? 运算符是完全等价的,而不仅仅是简化版本。 - Konrad Rudolph
显示剩余4条评论

32

这是一个不错的问题。VB.Net中的Select Case语句非常强大。

当然,也有标准的

Select Case Role
  Case "Admin"
         ''//Do X
  Case "Tester"
         ''//Do Y
  Case "Developer"
         ''//Do Z
  Case Else
       ''//Exception case
End Select

但这还不是全部...

你可以使用范围:

Select Case Amount
 Case Is < 0
    ''//What!!
 Case 0 To 15
   Shipping = 2.0
 Case 16 To 59
    Shipping = 5.87
 Case Is > 59
    Shipping = 12.50
 Case Else
    Shipping = 9.99
 End Select

还有更多...

你可以(尽管可能不是一个好主意)对多个变量进行布尔检查:

Select Case True
 Case a = b
    ''//Do X
 Case a = c
    ''//Do Y
 Case b = c
    ''//Do Z
 Case Else
   ''//Exception case
 End Select

5
实际上你错过了几个要点:a)使用“Select Case True”测试多个变量,b)使用“Case A, B, ...”形式,甚至c)应用冒号将执行语句与条件子句内联(尽管许多人不喜欢这样做)。 - RBarryYoung
6
请勿使用 Select Case True,只需使用 If 语句即可。 - Ryan Lundy
4
我发现使用"Select Case True"语句比"ifelse"语句更易读。 - dwidel
Select Case True 的问题在于它 看起来 好像会评估 每一个 Case 语句,并且运行每一个为真的代码。但实际上,它是逐个评估它们,并且只运行第一个为真的代码。如果要比较清晰地表达这种意思,If 语法则更好 (If...Else If...Else If...Else)。 - Ryan Lundy

31

最好且易用的CSV解析器:

Microsoft.VisualBasic.FileIO.TextFieldParser

通过添加对 Microsoft.VisualBasic 的引用,可以在任何其他 .Net 语言中使用,例如 C#


5
有趣的是,C# 开发者在没有考虑过这一点的情况下就开始使用 FileHelpers 库。我相信 FileHelpers 是很棒的,但它是一个外部依赖库。 - MarkJ
@MarkJ 我认为这是因为无知。 - Nathan Koop
我在谷歌上疯狂搜索这个类,但始终找不到,感谢你的标记! - pingoo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接