VB.NET的隐藏功能?

Hidden Features of VB.NET?

我从隐藏的功能中了解了不少当我找不到什么东西时感到惊讶类似于vb.net。

那么,它的一些隐藏的或鲜为人知的特征是什么呢?


Exception When条款在很大程度上是未知的。

考虑一下:

1
2
3
4
5
6
7
8
9
10
11
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


海关Enums

vb真正隐藏的特性之一是completionlistXML文档标记,可用于创建具有扩展功能的自己的Enum类型。不过,这项功能在C中不起作用。

我最近的代码中有一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
'
''' <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中可能值的智能感知列表。

编辑/编辑:

因为这是一个依赖于IDE的特性,所以当您使用它时很难显示它的外观,但我只使用一个屏幕截图:

行动中的完成列表http://page.mi.fu-berlin.de/krudolph/stuff/completion list.png

事实上,IntelliSense与使用Enum时获得的完全相同。


你注意到类似的比较运算符了吗?


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

更多来自MSDN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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*"


类型定义

vb通过Import别名知道一种原始的typedef

1
2
3
Imports S = System.String

Dim x As S ="Hello"

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

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


哦!不要忘记XML文本。

1
2
3
4
5
6
7
Dim contact2 = _
        <contact>
          <name>Patrick Hines</name>
          <%= From p In phoneNumbers2 _
            Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
          %>
        </contact>


对象初始化也在里面!

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


DirectCast

DirectCast是一个奇迹。在表面上,它的工作原理类似于CType操作符,因为它将对象从一种类型转换为另一种类型。但是,它的工作规则要严格得多。因此,CType的实际行为往往是不透明的,而且执行哪种转换一点也不明显。

DirectCast只支持两种不同的操作:

  • 取消对值类型的装箱,以及
  • 在类层次结构中向上转换。

任何其他强制转换都将不起作用(例如尝试将Integer取消绑定到Double),并将导致编译时/运行时错误(取决于情况和静态类型检查可以检测到的内容)。因此,我尽可能使用DirectCast,因为这最符合我的意图:根据具体情况,我要么取消对已知类型的值的绑定,要么执行上抛。故事的结尾。

另一方面,使用CType让代码的读者想知道程序员真正想要什么,因为它可以解决各种不同的操作,包括调用用户定义的代码。

为什么这是隐藏功能?vb团队发布了一个指南1,不鼓励使用DirectCast(尽管实际上速度更快!)为了使代码更统一。我认为这是一个不好的指导方针,应该颠倒过来:只要有可能,倾向于DirectCast而不是更一般的CType操作符。它使代码更加清晰。另一方面,仅当确实有意调用时,即当应调用收缩的CType运算符(参见运算符重载)时,才应调用CType

1)我无法找到该指南的链接,但我发现了Paul Vick的观点(VB团队的首席开发人员):

In the real world, you're hardly ever going to notice the difference, so you might as well go with the more flexible conversion operators like CType, CInt, etc.

(由扎克编辑:在这里了解更多信息:我应该如何在vb.net中进行强制转换?)


条件合并运算符

I don't know how hidden you'd call it, but the Iif([expression],[value if true],[value if false]) As Object function could count.

它不是隐藏的,而是弃用的!vb 9有一个更好的If操作符,它与c的条件和合并操作符(取决于您想要的)完全一样工作:

1
2
3
4
Dim x = If(a = b, c, d)

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

编辑以显示另一个示例:

这将适用于If(),但会引起IIf()的例外。

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


这是一个不错的。vb.net中的select case语句非常强大。

当然有标准

1
2
3
4
5
6
7
8
9
10
Select Case Role
  Case"Admin"
         ''//Do X
  Case"Tester"
         ''//Do Y
  Case"Developer"
         ''//Do Z
  Case Else
       ''//Exception case
End Select

但还有更多…

您可以选择范围:

1
2
3
4
5
6
7
8
9
10
11
12
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

甚至更多…

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

1
2
3
4
5
6
7
8
9
10
Select Case True
 Case a = b
    ''//Do X
 Case a = c
    ''//Do Y
 Case b = c
    ''//Do Z
 Case Else
   ''//Exception case
 End Select


最好且简单的csv解析器:

1
Microsoft.VisualBasic.FileIO.TextFieldParser

通过添加对Microsoft.VisualBasic的引用,可以将其用于任何其他.NET语言,例如C。#


我一直使用的一个主要省时方法是WITH关键字:

1
2
3
4
5
With ReallyLongClassName
    .Property1 = Value1
    .Property2 = Value2
    ...
End With

我只是不喜欢打字超过我必须!


  • Andalso/OrElse逻辑运算符

(编辑:在此了解更多信息:我是否应该始终使用Andalso和OrElse运算符?)


在VB中,这些运算符之间存在差异:

/Double\Integer忽略余数

1
2
3
4
5
6
7
8
9
10
Sub Main()
    Dim x = 9 / 5  
    Dim y = 9 \ 5  
    Console.WriteLine("item x of '{0}' equals to {1}", x.GetType.FullName, x)
    Console.WriteLine("item y of '{0}' equals to {1}", y.GetType.FullName, y)

    'Results:
    'item x of 'System.Double' equals to 1.8
    'item y of 'System.Int32' equals to 1
End Sub


方法中的静态成员。

例如:

1
2
3
4
5
Function CleanString(byval input As String) As String
    Static pattern As New RegEx("...")

    return pattern.Replace(input,"")
End Function

在上面的函数中,无论函数被调用多少次,模式正则表达式都只创建一次。

另一种用途是将"随机"实例保留在周围:

1
2
3
4
5
Function GetNextRandom() As Integer
    Static r As New Random(getSeed())

    Return r.Next()
End Function

此外,这与简单地将其声明为类的共享成员不同;以这种方式声明的项也保证是线程安全的。在这个场景中并不重要,因为表达式永远不会改变,但是在其他地方它可能会改变。


自定义事件

尽管很少有用,但事件处理可以大量定制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Public Class ApplePie
    Private ReadOnly m_BakedEvent As New List(Of EventHandler)()

    Custom Event Baked As EventHandler
        AddHandler(ByVal value As EventHandler)
            Console.WriteLine("Adding a new subscriber: {0}", value.Method)
            m_BakedEvent.Add(value)
        End AddHandler

        RemoveHandler(ByVal value As EventHandler)
            Console.WriteLine("Removing subscriber: {0}", value.Method)
            m_BakedEvent.Remove(value)
        End RemoveHandler

        RaiseEvent(ByVal sender As Object, ByVal e As EventArgs)
            Console.WriteLine("{0} is raising an event.", sender)
            For Each ev In m_BakedEvent
                ev.Invoke(sender, e)
            Next
        End RaiseEvent
    End Event

    Public Sub Bake()
        ''// 1. Add ingredients
        ''// 2. Stir
        ''// 3. Put into oven (heated, not pre-heated!)
        ''// 4. Bake
        RaiseEvent Baked(Me, EventArgs.Empty)
        ''// 5. Digest
    End Sub
End Class

然后可以以下方式测试:

1
2
3
4
5
6
7
8
9
10
11
12
Module Module1
    Public Sub Foo(ByVal sender As Object, ByVal e As EventArgs)
        Console.WriteLine("Hmm, freshly baked apple pie.")
    End Sub

    Sub Main()
        Dim pie As New ApplePie()
        AddHandler pie.Baked, AddressOf Foo
        pie.Bake()
        RemoveHandler pie.Baked, AddressOf Foo
    End Sub
End Module


我非常喜欢在VisualBasic2005中引入的"我的"名称空间。我的是多组信息和功能的快捷方式。它可以快速直观地访问以下类型的信息:

  • my.computer:访问与计算机相关的信息,如文件系统、网络、设备、系统信息等。它提供对许多非常重要的资源的访问,包括my.computer.network、my.computer.file system和my.computer.printers。
  • my.application:访问与特定应用程序相关的信息,如名称、版本、当前目录等。
  • my.user:访问与当前已验证用户相关的信息。
  • my.resources:以强类型方式访问驻留在资源文件中的应用程序使用的资源。
  • my.settings:以强类型方式访问应用程序的配置设置。


我刚找到一篇文章说的是"!"运算符,也称为"字典查找运算符"。以下是文章的摘录:http://panopticconcentral.net/articles/902.aspx

The technical name for the ! operator
is the"dictionary lookup operator." A
dictionary is any collection type that
is indexed by a key rather than a
number, just like the way that the
entries in an English dictionary are
indexed by the word you want the
definition of. The most common example
of a dictionary type is the
System.Collections.Hashtable, which
allows you to add (key, value) pairs
into the hashtable and then retrieve
values using the keys. For example,
the following code adds three entries
to a hashtable, and looks one of them
up using the key"Pork".

1
2
3
4
5
Dim Table As Hashtable = New Hashtable
Table("Orange") ="A fruit"
Table("Broccoli") ="A vegetable"
Table("Pork") ="A meat"
Console.WriteLine(Table("Pork"))

The ! operator can be used to look up
values from any dictionary type that
indexes its values using strings. The
identifier after the ! is used as the
key in the lookup operation. So the
above code could instead have been
written:

1
2
3
4
5
Dim Table As Hashtable = New Hashtable
Table!Orange ="A fruit"
Table!Broccoli ="A vegetable"
Table!Pork ="A meat"
Console.WriteLine(Table!Pork)

The second example is completely
equivalent to the first, but just
looks a lot nicer, at least to my
eyes. I find that there are a lot of
places where ! can be used, especially
when it comes to XML and the web,
where there are just tons of
collections that are indexed by
string. One unfortunate limitation is
that the thing following the ! still
has to be a valid identifier, so if
the string you want to use as a key
has some invalid identifier character
in it, you can't use the ! operator.
(You can't, for example, say
"Table!AB$CD = 5" because $ isn't
legal in identifiers.) In VB6 and
before, you could use brackets to
escape invalid identifiers (i.e.
"Table![AB$CD]"), but when we started
using brackets to escape keywords, we
lost the ability to do that. In most
cases, however, this isn't too much of
a limitation.

To get really technical, x!y works if
x has a default property that takes a
String or Object as a parameter. In
that case, x!y is changed into
x.DefaultProperty("y"). An interesting
side note is that there is a special
rule in the lexical grammar of the
language to make this all work. The !
character is also used as a type
character in the language, and type
characters are eaten before operators.
So without a special rule, x!y would
be scanned as"x! y" instead of"x !
y". Fortunately, since there is no
place in the language where two
identifiers in a row are valid, we
just introduced the rule that if the
next character after the ! is the
start of an identifier, we consider
the ! to be an operator and not a type
character.


这是内置的,比C有明显的优势。实现接口方法而不必使用相同名称的能力。

例如:

1
2
3
Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo

End Sub


强迫瓦尔

在VB中,如果将参数包装在一组额外的括号中,则可以重写该方法的byref声明并将其转换为byval。例如,以下代码生成4、5、5而不是4、5、6

1
2
3
4
5
6
7
8
9
10
11
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim R = 4
    Trace.WriteLine(R)
    Test(R)
    Trace.WriteLine(R)
    Test((R))
    Trace.WriteLine(R)
End Sub
Private Sub Test(ByRef i As Integer)
    i += 1
End Sub

请参见过程调用未修改的参数-基础变量


按名称和传递参数,因此对它们重新排序

1
2
3
4
5
Sub MyFunc(Optional msg as String="", Optional displayOrder As integer = 0)

    'Do stuff

End function

用途:

1
2
3
4
5
6
7
8
9
Module Module1

    Sub Main()

        MyFunc() 'No params specified

    End Sub

End Module

也可以使用":="参数规范以任意顺序调用:

1
MyFunc(displayOrder:=10, msg:="mystring")


从vb 8开始,using语句是新的,C从一开始就有了它。它会自动为您调用Dispose。

例如。

1
2
3
Using lockThis as New MyLocker(objToLock)

End Using


考虑以下事件声明

1
Public Event SomethingHappened As EventHandler

在C中,可以使用以下语法检查事件订阅服务器:

1
2
3
4
if(SomethingHappened != null)
{
  ...
}

但是,vb.net编译器不支持此功能。它实际上创建了一个在IntelliSense中不可见的隐藏私有成员字段:

1
2
3
If Not SomethingHappenedEvent Is Nothing OrElse SomethingHappenedEvent.GetInvocationList.Length = 0 Then
...
End If

更多信息:

http://jelle.druyts.net/2003/05/09/behindthescenesofeventsinvbnet.aspxhttp://blogs.msdn.com/vbteam/archive/2009/09/25/testing-events-for-nothing-null-doug-rothaus.aspx


如果您需要一个与关键字匹配的变量名,请用括号将其括起来。不是NEC。不过,这是最好的做法——但可以明智地使用。

例如

1
2
3
4
5
6
7
8
Class CodeException
Public [Error] as String
''...
End Class

''later
Dim e as new CodeException
e.Error ="Invalid Syntax"

例如,来自注释(@pondidum)的示例:

1
2
3
4
5
6
7
8
Class Timer
Public Sub Start()
''...
End Sub

Public Sub [Stop]()
''...
End Sub


导入别名在很大程度上也是未知的:

1
2
3
4
Import winf = System.Windows.Forms

''Later
Dim x as winf.Form


有几个关于XML文本的答案,但不是关于这个特定的案例:

您可以使用XML文本来包含字符串文本,否则需要对其进行转义。例如,包含双引号的字符串文本。

而不是这个:

1
2
Dim myString = _
   "This string contains""quotes"" and they're ugly."

您可以这样做:

1
2
Dim myString = _
    <string>This string contains"quotes" and they're nice.</string>.Value

如果您正在测试用于csv解析的文本,这尤其有用:

1
2
3
4
5
Dim csvTestYuck = _
   """Smith"",""Bob"",""123 Anywhere St"",""Los Angeles"",""CA"""

Dim csvTestMuchBetter = _
    <string>"Smith","Bob","123 Anywhere St","Los Angeles","CA"</string>.Value

(当然,您不必使用标签;您可以使用任何您喜欢的标签。)


日期时间可以通过将日期与#

1
Dim independanceDay As DateTime = #7/4/1776#

您还可以将类型推断与此语法一起使用

1
Dim independanceDay = #7/4/1776#

这比使用构造函数要好得多

1
Dim independanceDay as DateTime = New DateTime(1776, 7, 4)


一行中可以有两行代码。因此:

1
Dim x As New Something : x.CallAMethod


可选参数

选项比创建新的重载要容易得多,例如:

1
2
3
4
Function CloseTheSystem(Optional ByVal msg AS String ="Shutting down the system...")
   Console.Writeline(msg)
   ''//do stuff
End Function


将多个using语句堆叠/分组在一起:

1
2
3
4
5
6
7
8
9
10
11
12
Dim sql As String ="StoredProcedureName"
Using cn As SqlConnection = getOpenConnection(), _
      cmd As New SqlCommand(sql, cn), _
      rdr As SqlDataReader = cmd.ExecuteReader()

    While rdr.Read()

        ''// Do Something

    End While

End Using

公平地说,你也可以用C来做。但很多人对这两种语言都不了解。


带参数的属性

我一直在做一些C编程,发现了一个缺少VB.NET的特性,但这里没有提到。

如何做到这一点(以及C限制)的一个例子可以在以下位置看到:使用C中典型的get-set属性…带参数

我从那个答案中摘录了代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
Private Shared m_Dictionary As IDictionary(Of String, Object) = _
             New Dictionary(Of String, Object)

Public Shared Property DictionaryElement(ByVal Key As String) As Object
    Get
        If m_Dictionary.ContainsKey(Key) Then
            Return m_Dictionary(Key)
        Else
            Return [String].Empty
        End If
    End Get
    Set(ByVal value As Object)
        If m_Dictionary.ContainsKey(Key) Then
            m_Dictionary(Key) = value
        Else
            m_Dictionary.Add(Key, value)
        End If

    End Set
End Property


vb.net中的标题框可以通过旧的vb6 fxn实现:

1
StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID


我发现其中一个非常有用并且有助于解决许多错误的特性是显式地将参数传递给函数,特别是在使用可选函数时。

下面是一个例子:

1
2
3
Public Function DoSomething(byval x as integer, optional y as boolean=True, optional z as boolean=False)
' ......
End Function

然后你可以这样称呼它:

1
2
3
4
DoSomething(x:=1, y:=false)
DoSomething(x:=2, z:=true)
or
DoSomething(x:=3,y:=false,z:=true)

这是非常干净和无缺陷的,然后像这样调用函数

1
DoSomething(1,true)

  • 子命名空间在导入其父命名空间后在范围内。例如,不必导入system.io或说system.io.file就可以使用文件类,而只需说io.file。这是一个简单的例子:有些地方功能真的很有用,而C不这么做。


如果你不知道以下情况,你真的不会相信这是真的,这确实是C缺乏时间的事情:

(称为XML文本)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
Imports <xmlns:xs="System">

Module Module1

  Sub Main()
    Dim xml =
      <root>
        <customer id="345">
          <name>John</name>
          17</age>
        </customer>
        <customer id="365">
          <name>Doe</name>
          99</age>
        </customer>
      </root>

    Dim id = 1
    Dim name ="Beth"
    DoIt(
      <param>
        <customer>
          <id><%= id %></id>
          <name><%= name %></name>
        </customer>
      </param>
    )

    Dim names = xml...<name>
    For Each n In names
      Console.WriteLine(n.Value)
    Next

    For Each customer In xml.<customer>
      Console.WriteLine("{0}: {1}", customer.@id, customer..Value)
    Next

    Console.Read()
  End Sub

  Private Sub CreateClass()
    Dim CustomerSchema =
      XDocument.Load(CurDir() &"\customer.xsd")

    Dim fields =
      From field In CustomerSchema...<xs:element>
      Where field.@type IsNot Nothing
      Select
        Name = field.@name,
        Type = field.@type

    Dim customer =
      <customer> Public Class Customer
<%= From field In fields Select <f>
Private m_<%= field.Name %> As <%= GetVBPropType(field.Type) %></f>.Value %>

                     <%= From field In fields Select <p>
 
Public Property <%= field.Name %> As <%= GetVBPropType(field.Type) %>
 Get
Return m_<%= field.Name %>
End Get
 Set(ByVal value As <%= GetVBPropType(field.Type) %>)
 m_<%= field.Name %> = value
End Set
 End Property
</p>.Value %>
End Class</customer>

    My.Computer.FileSystem.WriteAllText("Customer.vb",
                                        customer.Value,
                                        False,
                                        System.Text.Encoding.ASCII)

  End Sub

  Private Function GetVBPropType(ByVal xmlType As String) As String
    Select Case xmlType
      Case"xs:string"
        Return"String"
      Case"xs:int"
        Return"Integer"
      Case"xs:decimal"
        Return"Decimal"
      Case"xs:boolean"
        Return"Boolean"
      Case"xs:dateTime","xs:date"
        Return"Date"
      Case Else
        Return"'TODO: Define Type"
    End Select
  End Function

  Private Sub DoIt(ByVal param As XElement)
    Dim customers =
      From customer In param...<customer>
      Select New Customer With
      {
        .ID = customer.<id>.Value,
        .FirstName = customer.<name>.Value
      }

    For Each c In customers
      Console.WriteLine(c.ToString())
    Next
  End Sub

  Private Class Customer
    Public ID As Integer
    Public FirstName As String
    Public Overrides Function ToString() As String
      Return <string>
ID : <%= Me.ID %>
Name : <%= Me.FirstName %>
             </string>.Value
    End Function

  End Class
End Module
'Results:

ID : 1
Name : Beth
John
Doe
345: 17
365: 99

看看BethMassi的XML文本提示/技巧。


您可以在一行中使用if。

1
If True Then DoSomething()


使用when优化错误处理

注意在Catch ex As IO.FileLoadException When attempt < 3行中使用when

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Do
  Dim attempt As Integer
  Try
    ''// something that might cause an error.
  Catch ex As IO.FileLoadException When attempt < 3
    If MsgBox("do again?", MsgBoxStyle.YesNo) = MsgBoxResult.No Then
      Exit Do
    End If
  Catch ex As Exception
    ''// if any other error type occurs or the attempts are too many
    MsgBox(ex.Message)
    Exit Do
  End Try
  ''// increment the attempt counter.
  attempt += 1
Loop

最近在vbrad中查看


这是一个有趣的,我还没见过;我知道它在2008年的对比赛中有效,至少:

如果你不小心用分号结束了你的vb行,因为你已经做了太多的c,分号会被自动删除。实际上,不可能(至少在2008年的Vs中)用分号意外地结束一个vb行。试试看!

(这并不完美;如果您在最终类名中间键入分号,它将不会自动完成类名。)


与vb中的c语言中的break不同,您可以使用ExitContinue您想要的块:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
For i As Integer = 0 To 100
    While True
        Exit While
        Select Case i
            Case 1
                Exit Select
            Case 2
                Exit For
            Case 3
                Exit While
            Case Else
                Exit Sub
        End Select
        Continue For
    End While
Next

在vb.net中声明数组时,始终使用"0到xx"语法。

1
Dim b(0 to 9) as byte 'Declares an array of 10 bytes

它非常清楚阵列的跨度。将其与等效物进行比较

1
Dim b(9) as byte 'Declares another array of 10 bytes

即使您知道第二个示例由10个元素组成,它也不明显。我不记得有多少次我看到一个程序员写的代码

1
Dim b(10) as byte 'Declares another array of 10 bytes

这当然是完全错误的。因为B(10)创建了一个11字节的数组。而且它很容易导致错误,因为它看起来对任何不知道该寻找什么的人都是正确的。

"0到xx"语法也适用于以下内容

1
2
Dim b As Byte() = New Byte(0 To 9) {} 'Another way to create a 10 byte array
ReDim b(0 to 9) 'Assigns a new 10 byte array to b

通过使用完整的语法,您还将向将来阅读代码的任何人演示您知道自己在做什么。


1
IIf(False, MsgBox("msg1"), MsgBox("msg2"))

结果如何?两个信息框!!!!!这是因为IIF函数在到达函数时评估两个参数。

vb有一个新的if操作符(就像c?操作员:

1
If(False, MsgBox("msg1"), MsgBox("msg2"))

将只显示第二个MsgBox。

一般来说,我建议您替换VB代码中的所有IIF,除非您希望它同时处理这两项:

1
Dim value = IIf(somthing, LoadAndGetValue1(), LoadAndGetValue2())

可以确保两个值都已加载。


在vb8和以前的vesion中,如果没有为引入的变量指定任何类型,则会自动检测到对象类型。在vb9(2008)中,如果选项infer设置为on(默认情况下为on),则Dim将充当c的var关键字。


类似于Parsa的答案,like运算符有许多可以与上面的简单通配符匹配的内容。读到上面的MSDN文档时,我差点从椅子上摔了下来。


选择case代替多个if/elseif/else语句。

在本例中假设简单几何对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Function GetToString(obj as SimpleGeomertyClass) as String
  Select Case True
    Case TypeOf obj is PointClass
      Return String.Format("Point: Position = {0}", _
                            DirectCast(obj,Point).ToString)
    Case TypeOf obj is LineClass
      Dim Line = DirectCast(obj,LineClass)
      Return String.Format("Line: StartPosition = {0}, EndPosition = {1}", _
                            Line.StartPoint.ToString,Line.EndPoint.ToString)
    Case TypeOf obj is CircleClass
      Dim Line = DirectCast(obj,CircleClass)
      Return String.Format("Circle: CenterPosition = {0}, Radius = {1}", _
                            Circle.CenterPoint.ToString,Circle.Radius)
    Case Else
      Return String.Format("Unhandled Type {0}",TypeName(obj))
  End Select
End Function


如果用[和]将名称括起来,则可以对属性和变量名称使用保留关键字。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
Public Class Item
    Private Value As Integer
    Public Sub New(ByVal value As Integer)
        Me.Value = value
    End Sub

    Public ReadOnly Property [String]() As String
        Get
            Return Value
        End Get
    End Property

    Public ReadOnly Property [Integer]() As Integer
        Get
            Return Value
        End Get
    End Property

    Public ReadOnly Property [Boolean]() As Boolean
        Get
            Return Value
        End Get
    End Property
End Class

'Real examples:
Public Class PropertyException : Inherits Exception
    Public Sub New(ByVal [property] As String)
        Me.Property = [property]
    End Sub

    Private m_Property As String
    Public Property [Property]() As String
        Get
            Return m_Property
        End Get
        Set(ByVal value As String)
            m_Property = value
        End Set
    End Property
End Class

Public Enum LoginLevel
    [Public] = 0
    Account = 1
    Admin = 2
    [Default] = Account
End Enum


可能这个链接有帮助

http://blogs.msdn.com/vbteam/archive/2007/11/20/hidden-gems-in-visual-basic-2008-amanda-silver.aspx


与C中的不同,在VB中,您可以依赖非空项的默认值:

1
2
3
4
5
6
7
8
9
Sub Main()
    'Auto assigned to def value'
    Dim i As Integer '0'
    Dim dt As DateTime '#12:00:00 AM#'
    Dim a As Date '#12:00:00 AM#'
    Dim b As Boolean 'False'

    Dim s = i.ToString 'valid
End Sub

而在C中,这将是一个编译器错误:

1
2
int x;
var y = x.ToString(); //Use of unassigned value


MyClass关键字提供了一种引用最初实现的类实例成员的方法,忽略任何派生类重写。


Nothing关键字可以表示默认值(T)或空值,具体取决于上下文。您可以利用这一点制作一个非常有趣的方法:

1
2
3
4
'''<summary>Returns true for reference types, false for struct types.</summary>'
Public Function IsReferenceType(Of T)() As Boolean
    Return DirectCast(Nothing, T) Is Nothing
End Function


记住,在默认情况下,vb.net项目的根命名空间是项目属性的一部分,这一点也很重要。默认情况下,此根命名空间将与项目同名。使用名称空间块结构时,名称实际上附加到根名称空间。例如:如果项目名为myproject,那么我们可以将变量声明为:

1
Private obj As MyProject.MyNamespace.MyClass

要更改根命名空间,请使用项目->属性菜单选项。也可以清除根命名空间,这意味着所有命名空间块都将成为它们所包含代码的根级别。


vb还提供onerror语句。但现在用的不多。

ZZU1〔11〕


别名命名空间

1
Imports Lan = Langauge

虽然它不是vb.net独有的,但在遇到命名空间冲突时常常被遗忘。


您可以使用REM注释行,而不是'. 不是非常有用,但有助于重要评论突出使用"!!!!!!!!或者什么。


可以为空的日期!这在数据库(在本例中是MSSQL服务器)中数据进出的情况下特别有用。我有两个过程来给我一个smalldatetime参数,用一个值填充。其中一个使用一个简单的旧日期并测试它是否有任何值,指定一个默认日期。另一个版本接受一个Nullable(Of Date),这样我就可以使日期没有值,接受存储过程中的任何默认值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
<System.Diagnostics.DebuggerStepThrough> _
Protected Function GP(ByVal strName As String, ByVal dtValue As Date) As SqlParameter
    Dim aParm As SqlParameter = New SqlParameter
    Dim unDate As Date
    With aParm
        .ParameterName = strName
        .Direction = ParameterDirection.Input
        .SqlDbType = SqlDbType.SmallDateTime
        If unDate = dtValue Then    'Unassigned variable
            .Value ="1/1/1900 12:00:00 AM" 'give it a default which is accepted by smalldatetime
        Else
            .Value = CDate(dtValue.ToShortDateString)
        End If
    End With
    Return aParm
End Function
<System.Diagnostics.DebuggerStepThrough()> _
Protected Function GP(ByVal strName As String, ByVal dtValue As Nullable(Of Date)) As SqlParameter
    Dim aParm As SqlParameter = New SqlParameter
    Dim unDate As Date
    With aParm
        .ParameterName = strName
        .Direction = ParameterDirection.Input
        .SqlDbType = SqlDbType.SmallDateTime
        If dtValue.HasValue = False Then
            '// it's nullable, so has no value
        ElseIf unDate = dtValue.Value Then    'Unassigned variable
            '// still, it's nullable for a reason, folks!
        Else
            .Value = CDate(dtValue.Value.ToShortDateString)
        End If
    End With
    Return aParm
End Function


我不知道你怎么会说它是隐藏的,但是If接线员可以算数。

在某种程度上,它与许多C语言中的EDOCX1(三元)或??操作符非常相似。但是,重要的是要注意,它确实评估了所有参数,因此重要的是不要传递任何可能导致异常(除非您希望传递)或可能导致意外副作用的内容。

用途:

1
2
Dim result = If(condition, valueWhenTrue, valueWhenFalse)
Dim value = If(obj, valueWhenObjNull)


1
2
3
4
5
6
7
8
9
Private Sub Button1_Click(ByVal sender As Button, ByVal e As System.EventArgs)
        Handles Button1.Click
    sender.Enabled = True
    DisableButton(sender)
End Sub

Private Sub Disable(button As Object)
    button.Enabled = false
End Sub

在这段代码中,您有2个(也许更多?)在C里你永远做不到的事情:

  • 处理按钮1。单击-将处理程序外部附加到事件!
  • VB的隐含性允许您将处理程序的第一个参数声明为expexted类型。在C中,不能将委托寻址到不同的模式,即使它是预期的类型。
  • 同样,在C语言中,你不能在对象上使用预期的功能——在C语言中,你可以梦想它(现在他们制作了动态关键字,但它远离了VB)。在C中,如果您要写入(new object())。启用,您将得到一个错误,即类型对象没有方法"启用"。现在,我不是一个会建议你,如果这是安全的或不安全的,信息是按原样提供的,你自己做,总线仍然,有时(像在与COM对象工作时)这是一件好事。当期望值肯定是一个按钮时,我个人总是写(发送者为按钮)。

    事实上:举个例子:

    1
    2
    3
    4
    Private Sub control_Click(ByVal sender As Control, ByVal e As System.EventArgs)
            Handles TextBox1.Click, CheckBox1.Click, Button1.Click
        sender.Text ="Got it?..."
    End Sub


    不能在VB中显式实现接口成员,但可以用不同的名称实现它们。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    Interface I1
        Sub Foo()
        Sub TheFoo()
    End Interface

    Interface I2
        Sub Foo()
        Sub TheFoo()
    End Interface

    Class C
        Implements I1, I2

        Public Sub IAmFoo1() Implements I1.Foo
            ' Something happens here'
        End Sub

        Public Sub IAmFoo2() Implements I2.Foo
            ' Another thing happens here'
        End Sub

        Public Sub TheF() Implements I1.TheFoo, I2.TheFoo
            ' You shouldn't yell!'
        End Sub
    End Class

    请在Microsoft Connect上投票支持此功能。


    我以前非常喜欢可选的函数参数,但现在我不得不在C和VB之间来回切换,所以使用它们的次数更少。C什么时候支持他们?C++,甚至C都有(类)!


    总有一天,基本用户没有引入任何变量。他们只是通过使用它们来介绍他们。vb的选项explicit是为了确保不会因输入错误而错误地引入任何变量而引入的。您可以随时将其关闭,体验我们与BASIC一起工作的日子。


    代码文件

    1
    2
    3
    4
    5
    6
    ''' <summary>
    '''
    ''' </summary>
    ''' <remarks></remarks>
    Sub use_3Apostrophe()
    End Sub

    ByVal和ByRef关键字之间的差异:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    Module Module1

        Sub Main()
            Dim str1 ="initial"
            Dim str2 ="initial"
            DoByVal(str1)
            DoByRef(str2)

            Console.WriteLine(str1)
            Console.WriteLine(str2)
        End Sub

        Sub DoByVal(ByVal str As String)
            str ="value 1"
        End Sub

        Sub DoByRef(ByRef str As String)
            str ="value 2"
        End Sub
    End Module

    'Results:
    'initial
    'value 2


    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    Sub Main()
        Select Case"value to check"
            'Check for multiple items at once:'
            Case"a","b","asdf"
                Console.WriteLine("Nope...")
            Case"value to check"
                Console.WriteLine("Oh yeah! thass what im talkin about!")
            Case Else
                Console.WriteLine("Nah :'(")
        End Select


        Dim jonny = False
        Dim charlie = True
        Dim values = New String() {"asdff","asdfasdf"}
        Select Case"asdfasdf"
            'You can perform boolean checks that has nothing to do with your var.,
            'not that I would recommend that, but it exists.'
            Case values.Contains("ddddddddddddddddddddddd")
            Case True
            Case"No sense"
            Case Else
        End Select

        Dim x = 56
        Select Case x
            Case Is > 56
            Case Is <= 5
            Case Is <> 45
            Case Else
        End Select

    End Sub

    方法的属性!例如,在设计期间不应可用的属性可以是1)隐藏在"属性"窗口中,2)未序列化(尤其是对用户控件或从数据库加载的控件而言,这会很烦人):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <System.ComponentModel.Browsable(False), _
    System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden), _
    System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Always), _
    System.ComponentModel.Category("Data")> _
    Public Property AUX_ID() As String
        <System.Diagnostics.DebuggerStepThrough()> _
         Get
            Return mAUX_ID
        End Get
        <System.Diagnostics.DebuggerStepThrough()> _
         Set(ByVal value As String)
            mAUX_ID = value
        End Set
    End Property

    如果您进行任何数量的调试(请注意,您仍然可以在函数中放置一个断点,但不能单步执行该函数),那么放入DebuggerStepThrough()也是非常有用的。

    此外,将事物分类的能力(例如,"数据")意味着,如果您确实希望属性显示在属性工具窗口中,那么特定属性将显示在该类别中。


    再次选择参数!

    1
    2
    3
    4
    5
    6
    7
    8
    Function DoSmtg(Optional a As string, b As Integer, c As String)
        'DoSmtg
    End

    ' Call
    DoSmtg(,,"c argument")

    DoSmtg(,"b argument")

    ME关键字

    "me"关键字在vb.net中是唯一的。我知道这很常见,但是"我"和"这个"的C等价物之间有区别。区别在于"this"是只读的,"me"不是。这在构造器中很有价值,在构造器中,您有一个变量的实例,希望该变量已经被构造为相等的,因为您可以将"me=the variable"设置为与"c"相反,在这里您必须手动复制变量的每个字段(如果有许多字段并且容易出错,这可能很糟糕)。C解决方法是在构造函数外部执行分配。也就是说,如果对象是自构造成一个完整的对象,那么现在需要另一个函数。