VB.NET的隐藏function?

我已经通过C#的隐藏特性了解了很多浏览内容,当我找不到类似于VB.NET的东西时,感到惊讶。

那么它的一些隐藏或较less已知的function是什么?

子句时的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 

自定义Enum

VB真正隐藏的function之一是completionlist XML文档标签,可用于创build具有扩展function的自己类Enumtypes。 虽然这个function在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的variables赋值时,IDE提供一个来自RuleTemplates的可能值的智能感知列表。

/编辑:

由于这是一个依赖于IDE的function,因此很难在使用它时显示它的外观,但是我只是使用屏幕截图:

完成列表在行动http://page.mi.fu-berlin.de/krudolph/stuff/completionlist.png

事实上,智能感知与使用Enum时得到的结果完全相同。

你有没有注意到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 "[AZ]" ' The following statement returns False (does "F" NOT occur in the ' ' set of characters from "A" through "Z"?)' testCheck = "F" Like "[!AZ]" ' 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[LP]#[!ce]" ' 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*" 

types定义

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

 Imports S = System.String Dim x As S = "Hello" 

与generics一起使用时,这更有用:

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

哦! 不要忘记XML文字 。

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

对象初始化也在那里!

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

DirectCast

DirectCast是一个奇迹。 从表面上看,它与CType运算符类似,它将对象从一种types转换为另一种types。 然而,它的工作更严格的一套规则。 CType的实际行为往往是不透明的,而且执行哪种转换并不明显。

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

  • 取消装箱的值types和
  • 在类层次结构中向上转换。

任何其他的强制转换都不起作用(例如试图将Integer转换为Double ),并且会导致编译时/运行时错误(取决于情况以及静态types检查可以检测到什么)。 因此,我会尽可能使用DirectCast ,因为这样可以最好地捕捉我的意图:根据具体情况,我可能要取消已知types的值或执行upcast。 故事结局。

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

为什么这是一个隐藏的function? VB小组已经发布了一个指导方针1 ,它不鼓励使用DirectCast (即使速度更快!),以使代码更加统一。 我认为这是一个不好的指导方针,应该颠倒: 只要有可能,赞成DirectCast而不是更一般的CType运算符。 它使代码更清晰。 另一方面, CType只有在确实有意的时候才能被调用,也就是说,应该调用一个缩小的CType运算符(参见运算符重载 )。


1)我找不到指南的链接,但是我发现Paul Vick是这样做的 (VB团队的首席开发人员):

在现实世界中,你几乎不会注意到其中的差异,所以你最好还是使用像CType,CInt等更灵活的转换运算符。


(由Zack编辑:在这里了解更多: 我应该怎样在VB.NET中投入? )

If有条件和合并操作符

我不知道你会怎样调用它,但是Iif([expression式],[值如果为真],[值如果为false])作为对象函数可以计数。

它不像已弃用那么隐蔽! VB 9的If运算符要好得多,并且和C#的条件运算符一样(取决于你想要的):

 Dim x = If(a = b, c, d) Dim hello As String = Nothing Dim y = If(hello, "World") 

编辑来显示另一个例子:

这将与If() ,但是会导致IIf()的exception

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

这是一个很好的。 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 

甚至更多…

你可以(虽然可能不是个好主意)对多个variables进行布尔检查:

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

我一直使用的一个主要时间节省是With关键字:

 With ReallyLongClassName .Property1 = Value1 .Property2 = Value2 ... End With 

我只是不喜欢打字比我必须!

最好的和容易的CSVparsing器:

 Microsoft.VisualBasic.FileIO.TextFieldParser 

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

  • 还有/或者是逻辑运算符

(编辑:在这里了解更多: 我应该总是使用AndAlso和OrElse运营商? )

方法中的静态成员。

例如:

 Function CleanString(byval input As String) As String Static pattern As New RegEx("...") return pattern.Replace(input, "") End Function 

在上面的函数中,模式正则expression式只能被创build一次,无论调用多less次函数。

另一个用途是保持“随机”的实例:

 Function GetNextRandom() As Integer Static r As New Random(getSeed()) Return r.Next() End Function 

此外,这与简单地将其声明为该类的共享成员并不相同; 以这种方式声明的项目也保证是线程安全的。 在这种情况下并不重要,因为expression将永远不会改变,但也有其他的地方可能。

在VB中这些操作符有所不同:

/Double
\Integer忽略余数

 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 

我非常喜欢在Visual Basic 2005中引入的“我的”命名空间是几组信息和function的快捷方式。 它提供了对以下types信息的快速直观访问:

  • My.Computer :访问与计算机相关的信息,如文件系统,networking,设备,系统信息等。它提供了许多非常重要的资源,包括My.Computer.Network,My.Computer.FileSystem和My .Computer.Printers。
  • My.Application :访问与特定应用程序相关的信息,如名称,版本,当前目录等
  • My.User :访问与当前authentication用户相关的信息。
  • My.Resources :以强types方式访问驻留在资源文件中的应用程序使用的资源。
  • My.Settings :以强types的方式访问应用程序的configuration设置。

自定义事件

虽然很less有用,事件处理可以大量定制:

 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 

这可以按照以下方式进行testing:

 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 

我刚刚find一篇文章谈论“!” 运算符,也称为“字典查找运算符”。 以下是文章摘录: http : //panopticoncentral.net/articles/902.aspx

!的技术名称! 操作符是“字典查找操作符”。 字典是任何一种按键索引而不是数字索引的集合types,就像英文词典中的条目按照您希望定义的词索引的方式一样。 字典types的最常见示例是System.Collections.Hashtable,它允许您将(键,值)对添加到散列表中,然后使用键检索值。 例如,下面的代码将三个条目添加到哈希表中,并使用键“Pork”查找其中的一个。

 Dim Table As Hashtable = New Hashtable Table("Orange") = "A fruit" Table("Broccoli") = "A vegetable" Table("Pork") = "A meat" Console.WriteLine(Table("Pork")) 

那! 运算符可用于从任何使用string索引其值的字典types查找值。 !!之后的标识符 在查找操作中用作键。 所以上面的代码可以写成:

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

第二个例子完全等同于第一个例子,但是看起来好多了,至less在我眼中。 我发现那里有很多地方! 可以使用,特别是当涉及到XML和网页,那里只有吨的收集是按string索引。 一个不幸的局限是,这个事情跟着! 仍然必须是一个有效的标识符,所以如果你想用作密钥的string中有一些无效的标识字符,你不能使用! 运营商。 (例如,你不能说“Table!AB $ CD = 5”,因为$在标识符中是不合法的。)在VB6和之前,你可以使用括号来转义无效标识符(即“Table![AB $ CD]“),但是当我们开始使用括号来转义关键字时,我们失去了这样做的能力。 然而,在大多数情况下,这不是一个太大的限制。

为了获得真正的技术性,x!y在x有一个默认的属性将String或Object作为参数的情况下工作。 在这种情况下,x!y被改为x.DefaultProperty(“y”)。 有趣的一面是,在语言的词汇语法中有一个特殊的规则来使这一切工作。 那! 字符也被用作语言中的字符types,字符在操作符之前被使用。 所以没有特殊的规则,x!y会被扫描为“x!y”而不是“x!y”。 幸运的是,由于在一行中两个标识符都是有效的语言中没有地方,所以我们刚刚介绍了如果下一个字符在! 是一个标识符的开始,我们考虑! 做一个操作员而不是一个字符。

这是内置的,与C#相比有一定的优势。 无需使用相同名称即可实现接口方法的能力。

如:

 Public Sub GetISCSIAdmInfo(ByRef xDoc As System.Xml.XmlDocument) Implements IUnix.GetISCSIInfo End Sub 

强制ByVal

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

 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 

请参阅没有被过程调用修改的参数 – 底层variables

按名称传递参数,并重新sorting

 Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0) 'Do stuff End function 

用法:

 Module Module1 Sub Main() MyFunc() 'No params specified End Sub End Module 

也可以按任意顺序使用“:=”参数指定来调用:

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

Using语句是VB 8以来的新特性,C#从一开始就具有它。 它调用为你自动处理。

例如

 Using lockThis as New MyLocker(objToLock) End Using 

Import aliases are also largely unknown:

 Import winf = System.Windows.Forms ''Later Dim x as winf.Form 

Consider the following event declaration

 Public Event SomethingHappened As EventHandler 

In C#, you can check for event subscribers by using the following syntax:

 if(SomethingHappened != null) { ... } 

However, the VB.NET compiler does not support this. It actually creates a hidden private member field which is not visible in IntelliSense:

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

更多信息:

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

If you need a variable name to match that of a keyword, enclose it with brackets. Not nec. the best practice though – but it can be used wisely.

例如

 Class CodeException Public [Error] as String ''... End Class ''later Dim e as new CodeException e.Error = "Invalid Syntax" 

eg Example from comments(@Pondidum):

 Class Timer Public Sub Start() ''... End Sub Public Sub [Stop]() ''... End Sub 

There are a couple of answers about XML Literals, but not about this specific case:

You can use XML Literals to enclose string literals that would otherwise need to be escaped. String literals that contain double-quotes, for instance.

而不是这个:

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

你可以这样做:

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

This is especially useful if you're testing a literal for CSV parsing:

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

(You don't have to use the <string> tag, of course; you can use any tag you like.)

DateTime can be initialized by surrounding your date with #

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

You can also use type inference along with this syntax

 Dim independanceDay = #7/4/1776# 

That's a lot nicer than using the constructor

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

You can have 2 lines of code in just one line. hence:

 Dim x As New Something : x.CallAMethod 

Optional Parameters

Optionals are so much easier than creating a new overloads, such as :

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

Title Case in VB.Net can be achieved by an old VB6 fxn:

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

Properties with parameters

I have been doing some C# programming, and discovered a feature that was missing that VB.Net had, but was not mentioned here.

An example of how to do this (as well as the c# limitation) can be seen at: Using the typical get set properties in C#… with parameters

I have excerpted the code from that answer:

 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