Hidden Features of VB.NET?
我从隐藏的功能中了解了不少当我找不到什么东西时感到惊讶类似于vb.net。
那么,它的一些隐藏的或鲜为人知的特征是什么呢?
考虑一下:
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 |
海关
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 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 |
现在,当为声明为
因为这是一个依赖于IDE的特性,所以当您使用它时很难显示它的外观,但我只使用一个屏幕截图:
行动中的完成列表http://page.mi.fu-berlin.de/krudolph/stuff/completion list.png
事实上,IntelliSense与使用
你注意到类似的比较运算符了吗?
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通过
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} |
- 取消对值类型的装箱,以及
- 在类层次结构中向上转换。
任何其他强制转换都将不起作用(例如尝试将
另一方面,使用
为什么这是隐藏功能?vb团队发布了一个指南1,不鼓励使用
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有一个更好的
1 2 3 4 | Dim x = If(a = b, c, d) Dim hello As String = Nothing Dim y = If(hello,"World") |
编辑以显示另一个示例:
这将适用于
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中,这些运算符之间存在差异:
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 |
我发现其中一个非常有用并且有助于解决许多错误的特性是显式地将参数传递给函数,特别是在使用可选函数时。
下面是一个例子:
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优化错误处理
注意在
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语言中的
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 |
通过使用完整的语法,您还将向将来阅读代码的任何人演示您知道自己在做什么。
结果如何?两个信息框!!!!!这是因为IIF函数在到达函数时评估两个参数。
vb有一个新的if操作符(就像c?操作员:
将只显示第二个MsgBox。
一般来说,我建议您替换VB代码中的所有IIF,除非您希望它同时处理这两项:
1 |
可以确保两个值都已加载。
在vb8和以前的vesion中,如果没有为引入的变量指定任何类型,则会自动检测到对象类型。在vb9(2008)中,如果选项infer设置为on(默认情况下为on),则
类似于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参数,用一个值填充。其中一个使用一个简单的旧日期并测试它是否有任何值,指定一个默认日期。另一个版本接受一个
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 |
我不知道你怎么会说它是隐藏的,但是
在某种程度上,它与许多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里你永远做不到的事情:
同样,在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 |
如果您进行任何数量的调试(请注意,您仍然可以在函数中放置一个断点,但不能单步执行该函数),那么放入
此外,将事物分类的能力(例如,"数据")意味着,如果您确实希望属性显示在属性工具窗口中,那么特定属性将显示在该类别中。
再次选择参数!
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解决方法是在构造函数外部执行分配。也就是说,如果对象是自构造成一个完整的对象,那么现在需要另一个函数。