Hidden Features of VB.NET?
Asked Answered
B

64

121

I have learned quite a bit browsing through Hidden Features of C# and was surprised when I couldn't find something similar for VB.NET.

So what are some of its hidden or lesser known features?

Bisayas answered 19/9, 2008 at 14:7 Comment(0)
H
128

The Exception When clause is largely unknown.

Consider this:

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
Hiding answered 19/9, 2008 at 14:16 Comment(4)
useful if you wish to catch a specific SQLException, say -2 which if i remember correctly is network timeout: Catch ex as sqlException where ex.code = -2Equidistant
Wow! I just read this and put it to use immediately to simplify a try/catch block I just wrote last week. I never new this existed.Snobbish
+1 And here's where the NET CLR team blog explains why exception filters are useful blogs.msdn.com/clrteam/archive/2009/02/05/…Pedicure
Not only is this hidden, but it is also not available in C#.Chamaeleon
D
82

Custom Enums

One of the real hidden features of VB is the completionlist XML documentation tag that can be used to create own Enum-like types with extended functionality. This feature doesn't work in C#, though.

One example from a recent code of mine:

'
''' <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

Now, when assigning a value to a variable declared as Rule, the IDE offers an IntelliSense list of possible values from RuleTemplates.

/EDIT:

Since this is a feature that relies on the IDE, it's hard to show how this looks when you use it but I'll just use a screenshot:

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

In fact, the IntelliSense is 100% identical to what you get when using an Enum.

Dannica answered 19/9, 2008 at 14:22 Comment(8)
Interesting - could you show an example of how this looks when you consume it?Fuge
It looks like someone could still create their own rule by calling the Rule constructor directly? If so, and if you wanted to stop this, could you declare the constructor as "Friend" in your library?Dragonfly
Joel, in my example code I intentially didn't forbid this. Rather, I offer the user some common rules and allow the creation of own, specialized rules. You can of course prevent this by marking the constructor as friend or by using the same class as the enum: Rule instead of RuleTemplate.Dannica
is there somewhere with a list of hidden useful attribute uses? this one at face seems incredible, but I'm not sure yet where I would use it or if it could solve a primary gripe in some cases with having no ability to have a generic restricted to enums.Liard
@Maslow: there's not attribute involved here. That is an xml comment.Dragonfly
@Joel: please enlighten me: how did you prevent highlighting the comment?Dannica
You can also make a class its own completion list.Elseelset
Definately a nice bonus when combined with the Strategy pattern (as your example shows)Ramsden
E
49

Have you noticed the Like comparison operator?

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

More from 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*"
Edwards answered 19/9, 2008 at 14:7 Comment(8)
wait, what? That's new to me! Hmm, that's a helluva lot better than the alternative with VB.NET string manipulation :DRamsden
..!! I didn't know that although I worked on several vb.net projects! Interesting feature...Joanajoane
woooooooooooooooooooooooow! thanks! that's awsome! does it work in ELinq, DLinq too? what about XLinq?Wunderlich
@dotjoe Hmm? There's nothing 'lazy' about these globs.Bahner
How does this perform, whats happening under the hood? Is it s synonym for reg ex libraries?Deery
Nope, compiles to a simple call to a static function: Microsoft.VisualBasic.CompilerServices.LikeOperator.LikeString. It may look like a cheat to some people, but it gets very interesting when it comes to LINQ.Hoiden
This 'hidden feature' was was in VB6. The book I learnt VB6 included it so I've always known of its existence.Restful
"Like" is my favorite handy VB string tool ever. As a perl and regex fanatic, I much appreciate the capability.Farquhar
D
48

Typedefs

VB knows a primitive kind of typedef via Import aliases:

Imports S = System.String

Dim x As S = "Hello"

This is more useful when used in conjunction with generic types:

Imports StringPair = System.Collections.Generic.KeyValuePair(Of String, String)
Dannica answered 19/9, 2008 at 14:40 Comment(5)
please show an example the word Import is unrecognized in my IDE.Wunderlich
Imports it should be. ;-) Somehow, this error has gone undetected (and garnered 28 upvotes) for nearly a whole year.Dannica
I always wondered how i could make a new "type" with defaults for a generic! Cool!Voroshilovgrad
Import, Imports, Importz, whatever! Sheesh, you think we read these posts before we upvote them!Pedicure
Superb for using xunit in visual studio tests i.e. Imports Assert = xUnit.AssertBoswall
C
45

Oh! and don't forget XML Literals.

Dim contact2 = _
        <contact>
          <name>Patrick Hines</name>
          <%= From p In phoneNumbers2 _
            Select <phone type=<%= p.Type %>><%= p.Number %></phone> _
          %>
        </contact>
Calebcaledonia answered 19/9, 2008 at 14:34 Comment(4)
That's what I was going to say. In fact, I've used XML literals for a purpose in which it wasn't intended. I used it to produce Javascript... swortham.blogspot.com/2009/03/vb-2008.htmlAstrakhan
Among other things, you can use XML Literals to get around ugly string escaping, e.g. when you're using strings that themselves contain double quotes. Just put the string inside an XML Literal and call Value, like this: <string>This string contains "quotes" and it's OK.</string>.Value (I found this especially handy when writing tests on parsing CSV files where every field was in quotes. It would not have been fun to escape all those quotes by hand in my test lines.)Gerrigerrie
@Kyralessa: +1, great comment. In fact, it's also a great way to specify multi-line strings (hugs SQL statements, etc.).Irv
Inline XML is one of the worst VB.NET features ever to be conceived. Unsubstantiated fact.Harlotry
C
39

Object initialization is in there too!

Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
Calebcaledonia answered 19/9, 2008 at 14:17 Comment(3)
I can't believe they went with curly braces. We already have a With statement.. they could have just reused that syntax.Equities
I know, it's made just to show you that there is no cop on the road... lol JKWunderlich
Thi sis what happens when all of the compiler writers are themselves C/C++ programmers at heart. They keep slipping C syntax into other languages because they cannot conceive of anything being better.Maxama
D
38

DirectCast

DirectCast is a marvel. On the surface, it works similar to the CType operator in that it converts an object from one type into another. However, it works by a much stricter set of rules. CType's actual behaviour is therefore often opaque and it's not at all evident which kind of conversion is executed.

DirectCast only supports two distinct operations:

  • Unboxing of a value type, and
  • upcasting in the class hierarchy.

Any other cast will not work (e.g. trying to unbox an Integer to a Double) and will result in a compile time/runtime error (depending on the situation and what can be detected by static type checking). I therefore use DirectCast whenever possible, as this captures my intent best: depending on the situation, I either want to unbox a value of known type or perform an upcast. End of story.

Using CType, on the other hand, leaves the reader of the code wondering what the programmer really intended because it resolves to all kinds of different operations, including calling user-defined code.

Why is this a hidden feature? The VB team has published a guideline1 that discourages the use of DirectCast (even though it's actually faster!) in order to make the code more uniform. I argue that this is a bad guideline that should be reversed: Whenever possible, favour DirectCast over the more general CType operator. It makes the code much clearer. CType, on the other hand, should only be called if this is indeed intended, i.e. when a narrowing CType operator (cf. operator overloading) should be called.


1) I'm unable to come up with a link to the guideline but I've found Paul Vick's take on it (chief developer of the VB team):

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.


(EDIT by Zack: Learn more here: How should I cast in VB.NET?)

Dannica answered 19/9, 2008 at 16:6 Comment(5)
I actually like TryCast() a bit better. It won't throw an exception, just return Nothing if the cast fails. If you expect the cast to fail often, it's faster than If TypeOf x Is T...DirectCast(x,T) and certainly faster than catching the exception if DirectCast fails.Corrasion
DirectCast() and TryCast() are invaluable when used correctly as a pair. DirectCast() should be used if the object being cast is always expected to be the target type (if it isn't you'll get an error, a good thing since it's an unexpected situation). TryCast() should be used if the object being cast could be of the target type, or of several target types. Using One or the other exclusively will either lead to extra overhead (if typeof x is y then directcast(x, y) is inefficient) or to avoiding valid errors (using TryCast() for cases where the object should always be the target type)Ramsden
Yoooder: 100% correct. It's a shame I didn't mention TryCast back then since I mainly had a bone to pick with the pervasive use of CType.Dannica
@Maslow: of course it doesn't, since Enums are value types and TryCast only works on reference types, as per the documentation.Dannica
+1: Heh. I've got to admit, I just read this and thought "Oh yeah, DirectCast, how did I forget about that?" And then I used it on my very next line of code (as I really dislike CType).Maxama
D
37

If conditional and coalesce operator

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.

It's not so much hidden as deprecated! VB 9 has the If operator which is much better and works exactly as C#'s conditional and coalesce operator (depending on what you want):

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

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

Edited to show another example:

This will work with If(), but cause an exception with IIf()

Dim x = If(b<>0,a/b,0)
Dannica answered 19/9, 2008 at 14:14 Comment(9)
Nice, I didn't know this! I just used IIF yesterday so I'm going to revisit that code block.Bisayas
Nice to know. It's not exactly deprecated, though, if your job has you targeting the 2.0 framework.Colvin
It is deprecated and it doesn't matter which platform you target, the new If operator works on both since it's a language feature that doesn't rely on the framework.Dannica
Tell VS 2005 that. Not all of us get to work with the latest and greatest.Colvin
Only and huuuge problem with this it's not type-safety, it returns and object which is rubbish 99% of the time.Pullulate
@Slough, nonsense. This method is 100% type safe and it returns an object of the same type as its (second and third) argument. Additionally, there must be a widening conversion between the arguments, else there will be a compile error because the types don't match.Dannica
Yes, its IIf() that is not type safeEquidistant
Sort of a simplified trinary operator, providing some equivalence to C & perl's ? operator.Farquhar
@Farquhar In fact, it’s completely equivalent to C and Perl’s :? operator, it’s not just a simplified version.Dannica
H
32

This is a nice one. The Select Case statement within VB.Net is very powerful.

Sure there is the standard

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

But there is more...

You can do ranges:

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

And even more...

You can (although may not be a good idea) do boolean checks on multiple 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
Hiding answered 26/12, 2008 at 19:59 Comment(4)
Actually you missed a couple: a) use of "Select Case True" to test more than one variable, b) use of "Case A, B, ..." form, and even c) applying the ":" to in-line the execution statement with the condition clause (though many do not like this).Maxama
Please don't use Select Case True. Just use an If statement.Gerrigerrie
I find Select Case True much easier to read than a giant ifelse statement.Elata
The trouble with Select Case True is that it looks as if it evaluates each of the Case statements and runs the code for each one which is true. But in fact it evaluates them one-by-one and only runs the code for the first one which is true. The syntax for If is much clearer in this regard (If...Else If...Else If...Else).Gerrigerrie
R
31

The best and easy CSV parser:

Microsoft.VisualBasic.FileIO.TextFieldParser

By adding a reference to Microsoft.VisualBasic, this can be used in any other .Net language, e.g. C#

Ruggles answered 19/9, 2008 at 14:7 Comment(3)
+1 It's weird how the C# folks run to FileHelpers without ever considering this. I'm sure FileHelpers is excellent, but it is an external dependency.Pedicure
@Pedicure I presume it's because of ignoranceLandgrabber
I googled the hell out of trying to find this class and never did, thanks for flaging it up!Harbourage
G
31

One major time saver I use all the time is the With keyword:

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

I just don't like typing more than I have to!

Ghyll answered 19/9, 2008 at 14:10 Comment(9)
But it also create some hidden bugs, especially when you have With within WithFroggy
I didn't even know you could put a new With within an existing With. That's just sloppy!Corrasion
2Bob: it's not sloppy, I'd suggest.. it's just a language construct to be used with care. For setting lots of properties in successive lines, it's great, but finding a random .Foo in a complex piece of code and then having to hunt the With statement x lines above is not a good use of the feature.Seep
Wish C# has this? Or have I been asleep and is that in the C# hidden-features answers already...? ;-)Kamp
Also... during debugging you can't step over and see the value of the property... you must took the ReallyLongClassName into the Watch list.Accentor
@Romias: wrong. The debugger can indeed show the value of a with block member in a hover-over.Equities
@Boo: You're right but it's still an annoyance that you can't add it to the Watch list.Joanajoane
Gotta agree, unless you just prefer the style of dense text in your code (ugh)Cressi
I just thought I'd mention: With can be dangerous in a multithreaded environment since the compiler creates a local variable that is only in-scope within the With block. If something is posted to another thread and not processed until after the With block is exited, you can unexpectedly get a null reference. Maybe this is obvious to everyone else, but that fact burned me before. See the answer to this question for an example.Alcove
D
26
  • AndAlso/OrElse logical operators

(EDIT: Learn more here: Should I always use the AndAlso and OrElse operators?)

Dragonfly answered 19/9, 2008 at 14:10 Comment(1)
I wouldn't call it hidden at all, If Contact IsNot Nothing AndAlso Contact.ContactId > 0 Then Do it, If you will use And you will have an exception thrown.Wunderlich
W
25

In vb there is a different between these operators:

/ is Double
\ is Integer ignoring the remainder

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
Waiver answered 19/9, 2008 at 14:7 Comment(1)
i learned this the hard way when trying to find a needle in a million lines of code. regular versus integer division. good tip!Nightly
D
25

Static members in methods.

For example:

Function CleanString(byval input As String) As String
    Static pattern As New RegEx("...")

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

In the above function, the pattern regular expression will only ever be created once no matter how many times the function is called.

Another use is to keep an instance of "random" around:

Function GetNextRandom() As Integer
    Static r As New Random(getSeed())

    Return r.Next()
End Function 

Also, this isn't the same as simply declaring it as a Shared member of the class; items declared this way are guaranteed to be thread-safe as well. It doesn't matter in this scenario since the expression will never change, but there are others where it might.

Dragonfly answered 3/10, 2008 at 16:49 Comment(7)
One use of this is to keep a counter that will increment each time the method is called. If the variable is marked Static, it won't be reinitialized on each method call; it'll only be initialized on the first call, and thereafter will retain its value.Gerrigerrie
This is the reason why static class members are named "shared" in VB.NETCatholicon
Static is bad form in VB.NET even more than it was in classic VB. Static variables should be avoided whenever and wherever possible.Equities
@Boo - that's pretty sweeping. What's your justification? I think static variables are useful.Pedicure
Static, used as in the examples above, allows a unique form of encapsulation: class-level variables that have method-level scope. Without it, you'd have to create a class-level variable that would be accessible to any class member, even if you're only using it in one method.Gerrigerrie
@Enrico, well that's part of it. But also static isn't really an OOP term. It's more of a assmebly/C term meaning "this field is in a fixed place in memory".Astigmatic
beware: I believe it is only 'static' for multiple calls to the method in that particular object, NOT across all instances of the object. Tell me if I'm wrong, start your message with @fastalKaolinite
D
23

Custom Events

Though seldom useful, event handling can be heavily customized:

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

This can then be tested in the following fashion:

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
Dannica answered 19/9, 2008 at 17:20 Comment(4)
seems cool, but if I ever need this I think I will have done something wrong ;-). It just seems against the KISS principle.Contra
It is really, really useful when you want to make sure every sink gets the event even if one or more throw an exception.Astigmatic
Another value (I just read it on the MSDN site) is if your class throws lots of events, you can force it to use a hash table/dictionary as a container, rather than declaring a field for each event. msdn.microsoft.com/en-us/library/8627sbea(VS.71).aspxHiding
Cool. I thought this one of the features that set apart C# and VB.NET (as in one can, but the other has no syntax for it). Nice to at least know I was wrong in this respect.Kamp
R
23

I really like the "My" Namespace which was introduced in Visual Basic 2005. My is a shortcut to several groups of information and functionality. It provides quick and intuitive access to the following types of information:

  • My.Computer: Access to information related to the computer such as file system, network, devices, system information, etc. It provides access to a number of very important resources including My.Computer.Network, My.Computer.FileSystem, and My.Computer.Printers.
  • My.Application: Access to information related to the particular application such as name, version, current directory, etc.
  • My.User: Access to information related to the current authenticated user.
  • My.Resources: Access to resources used by the application residing in resource files in a strongly typed manner.
  • My.Settings: Access to configuration settings of the application in a strongly typed manner.
Rabi answered 10/10, 2008 at 11:13 Comment(3)
This is just great and every vb.net guy out there should know stuff in My namespace, it's so useful.Pullulate
My.* FTW :) .Pullulate
It's sort of useful, but I hate the dumbed down name. Reminds me of this secretgeek.net/refactvb.aspPedicure
H
21

I just found an article talking about the "!" operator, also know as the "dictionary lookup operator". Here's an excerpt from the article at: http://panopticoncentral.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".

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:

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.

Hiding answered 19/9, 2008 at 14:7 Comment(8)
Didn't know that was possible in VB.NET, although looking bad :)Pullulate
That's one of those features I used then intentionally forgot. It saves a few keystrokes but messes with my code highlighting and readability. forgetting again right.... NOWRamsden
Interesting, but not really useful. Is this the kind of stuff the VB team works on instead of adding missing features like the yield keyword? :PJoanajoane
This feature is carried for backward compatibility from VB3 (AFAIK)Edwards
do those classes that implement a keyed index have a common interface they inherit from? like IKeyed the same way integer indexed containers implement IENumberable?Liard
Integer index is IList, not IEnumerableDragonfly
This feature also works with DataRows (i.e. dr!ID) which is VERY handy in LINQ to DataSets.Tasimeter
Nope, it just looks for a default property that takes a string parameter.Astigmatic
H
19

This is built-in, and a definite advantage over C#. The ability to implement an interface Method without having to use the same name.

Such as:

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

End Sub
Hiding answered 19/9, 2008 at 14:28 Comment(6)
Im pritty sure that you can do something like this in C#. In VB.NET its just forced, and in C# its optional?Bayne
You can also make the sub private, which is a great way to hide stuff like the calls to non-generic deprecated versions of interfaces.Counterfactual
It can be a good idea. The classic example would be if you want a Public Close method that also acts as your Dispose implementation for IDisposable.Pedicure
That's also pretty useful if you happen to implement two interfaces that share a method name.Admire
I've seen this and always wish I hadn't. Should not be allowed.Kaolinite
You can actually do this in C#, it's just not as intuitive and obvious what you're doing.Edric
W
17

Forcing ByVal

In VB, if you wrap your arguments in an extra set of parentheses you can override the ByRef declaration of the method and turn it into a ByVal. For instance, the following code produces 4, 5, 5 instead of 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

See Argument Not Being Modified by Procedure Call - Underlying Variable

Wiredraw answered 19/9, 2008 at 14:7 Comment(2)
Oh my goodness... that's a remarkable feature, though I don't think I'd know what it was doing if I read it in someone else's code. If you have to comment it just to know what it's doing, you might as well have made the throw away variable to pass in instead.Rhodesia
This is actually a side effect of the use of parenthesis - Parenthesis create a temp value of what's inside, even if just one item. This effect KILLED ME in vb6 - Sub calls didn't take parens, but me coming from C instinctively put the parens in. 6.0 blew up on multiple parameters, but for one parameter subs, it happily passed a temp value and REFUSED to honor my 'byref'. Happened about every 3 years, about the time it took me to forget the last incident.Kaolinite
D
16

Passing parameters by name and, so reordering them

Sub MyFunc(Optional msg as String= "", Optional displayOrder As integer = 0)

    'Do stuff

End function

Usage:

Module Module1

    Sub Main()

        MyFunc() 'No params specified

    End Sub

End Module

Can also be called using the ":=" parameter specification in any order:

MyFunc(displayOrder:=10, msg:="mystring")
Dallon answered 19/9, 2008 at 14:7 Comment(4)
Wow, this is super cool! I seen this when using Web Services, etc but I didn't know you could do this any any ol' normal method.Triplicate
Definately a very handy tool when you encounter a method that takes too many arguments. I try to name each parameter and put the name:=value on its own line. It's a lot more intuitive and clean for methods that take > 5 (my rule of thumb) parameters.Ramsden
Especially useful for Office automation, where you have to cope with methods with dozens of optional arguments.Pedicure
What's also cool is that you can mix the two: start by specifying the required parameters in order, then switch to named parameters for the optional arguments!Maxama
H
15

The Using statement is new as of VB 8, C# had it from the start. It calls dispose automagically for you.

E.g.

Using lockThis as New MyLocker(objToLock)

End Using
Hiding answered 19/9, 2008 at 14:24 Comment(2)
It's worth noting (only because I've forgotten at least twice) that you can have one Using statement wrap several Disposable objects. The syntax is "Using objA as new object, objB as new object...." It's a lot cleaner than nesting multiple Using statements.Ramsden
Definately one of my favorites as well.Equities
H
14

Import aliases are also largely unknown:

Import winf = System.Windows.Forms

''Later
Dim x as winf.Form
Hiding answered 19/9, 2008 at 14:22 Comment(3)
I think we had the same idea.Contra
@Boo -- here's a simple example where import aliases are not evil. #93369Hiding
Okay - there's an obvious avenue for abuse, but regardless of @torial's rant this is a great feature. Everytime I include System.Text.RegularExpressions I risk having name collisions with the "Group" class since that's a common class name. The alias lets you avoid having to fully qualify ambiguous classes which is a huge time saver and actually enhances readability when used properly. The feature is great, but your specific example does sort of invite some ridicule - sorry to say.Rhodesia
H
14

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.

e.g.

Class CodeException
Public [Error] as String
''...
End Class

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

e.g. Example from comments(@Pondidum):

Class Timer
Public Sub Start()
''...
End Sub

Public Sub [Stop]()
''...
End Sub
Hiding answered 19/9, 2008 at 14:48 Comment(4)
I think this example would be better if you didn't use "If" as the example keyword.Bisayas
timer.Start and timer.Stop spring to mind as examples of good use of thisEquidistant
+1 for pointing it out with a disclaimer. There are several framework classes that require this to resolve correctly, such as [Assembly]Ramsden
[Enum] is another good example of a case where you need the brackets in order to use the class instead of the keyword.Gerrigerrie
H
14

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

More Information:

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

Harlandharle answered 19/9, 2008 at 16:44 Comment(4)
Why would you ever want to do that? I can't imagine a use case where you need to know the number of subscribers to an event in VB.Dannica
In certain circumstances, C# throws an exception if you raise the event and there are no handlers. VB.Net will not. Hence the need to check.Dragonfly
I used this for a business object event which raised validation error messages to the subscribers. I wanted to check to see if the event was being handled so that I knew the validation errors were being received. Otherwise, I had the business object throw an exception.Harlandharle
Another handy use for this private member is to get the Event's invocation list. I've used it in several cases to fire the event in an async manner to all callers (prevents Listener A from modifying the event before Listener B receives it; also it prevents Listener A from delaying the delivery to Listener B). I've used this a lot in custom data sync scenarios, and also in APIs.Ramsden
G
13

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.

Instead of this:

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

You can do this:

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.)

Gerrigerrie answered 19/9, 2008 at 14:7 Comment(1)
<q> would be a good tag, similar to usage in Perl/Ruby. Anyway, that’s quite a nice idiom. LIKE!Dannica
S
12

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)
Shrike answered 19/9, 2008 at 14:7 Comment(1)
Not if you have Option Strict OnShrike
H
12

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

Dim x As New Something : x.CallAMethod
Hoiden answered 19/9, 2008 at 14:7 Comment(4)
whoa... i thought this was only possible w/class and inheritanceStorfer
Don't forget Call (New Something).CallAMethod()Astigmatic
This is a holdever from MS-Basic on the Apple ][! In my shop I would be just as ridiculed for using Gotos :-/Kaolinite
Most of the time this is to be avoided but where I like to use it is in case statements where the lines are really short e.g. Case 4:x=22Elata
P
11

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
Pullulate answered 27/11, 2008 at 16:24 Comment(3)
I wasn't aware that C# was going to get them. They are nice, but you have to be careful to use them only where you're sure the code won't be consumed by C# since it doesn't support them. FxCop/Code Analysis will tell you to overload the method instead.Ramsden
...I just found a great use for Optional parameters, while still keeping them out of production code. I wrote-up a short post about it on my site: yoooder.com/wordpress/?p=62Ramsden
Ah, I despise this so much... But useful for Office automationPredominance
D
9

Stack/group multiple using statements together:

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

To be fair, you can do it in C#, too. But a lot of people don't know about this in either language.

Dragonfly answered 19/9, 2008 at 14:7 Comment(5)
@ck - how is this done with C#? Can you please provide a link, sorry from all the VBers, I am also one, but education is before manners...Wunderlich
@Shimmy: if they are of the same type you can just comma delimit them. If they are different types, each gets it's own using statement, but the additional objects go on a new line (without the need for a new scope block). I have an example handy at this question: stackoverflow.com/questions/436026Dragonfly
I cannot see how this could be practical in any code, especially for readability.Pumpkinseed
@Pumpkinseed - I provided a very practical, readable, and common example.Dragonfly
@Joel I meant 'practical' in the sense that in a workplace where everyone has their own coding style writing using statements like this could cause some issues. I can imagine other co-workers seeing this and cleaning it up as they think its 'abnormal' or something. Don't get me wrong its a cool concept.Pumpkinseed
H
9

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
Hiding answered 19/9, 2008 at 14:7 Comment(2)
This is interesting, but I'm not entirely sure where this would be useful. myObj.Something("abc") looks more like you're accessing a Function than a property. Not sure what this buys you.Rhodesia
I hate ambiguity. What should it be. A method, or a property. Some refactoring tools suggest creating both in certain situations too, looks like they dont even know...Deery
H
9

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

StrConv(stringToTitleCase, VbStrConv.ProperCase,0) ''0 is localeID
Hiding answered 19/9, 2008 at 14:51 Comment(2)
its also in the textinfo class. not sure what namespace that is in. probably system.textBenign
You are better of to be .net language neutral and use the Globalization TextInfo class to convert ToTitleCase. If you code ever needs to be converted to C# you'll have lots of little nasties that require Microsoft.VisualBasicPumpkinseed
S
8

One of the features I found really useful and helped to solve many bugs is explicitly passing arguments to functions, especially when using optional.

Here is an example:

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

then you can call it like this:

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

This is much cleaner and bug free then calling the function like this

DoSomething(1,true)
Seniority answered 19/9, 2008 at 14:7 Comment(0)
E
7

Refined Error Handling using When

Notice the use of when in the line Catch ex As IO.FileLoadException When attempt < 3

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

Recently viewed in VbRad

Edwards answered 19/9, 2008 at 14:7 Comment(0)
W
7

If you never knew about the following you really won't believe it's true, this is really something that C# lacks big time:

(It's called XML literals)

Imports <xmlns:xs="System">

Module Module1

  Sub Main()
    Dim xml =
      <root>
        <customer id="345">
          <name>John</name>
          <age>17</age>
        </customer>
        <customer id="365">
          <name>Doe</name>
          <age>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.<age>.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

Take a look at XML Literals Tips/Tricks by Beth Massi.

Waiver answered 19/9, 2008 at 14:7 Comment(4)
Show 'em one with substitutions.Schick
I don't know if that's what it's called. I'll add one.Schick
Naturally when I went to test it, it broke.Schick
I tested it and it works great. What .Net Version do you use?Wunderlich
H
7

You can have an If in one line.

If True Then DoSomething()
Hoiden answered 19/9, 2008 at 14:7 Comment(3)
or If x = 0 Then : Do0() : ElseIf x = 1 Then Do1() : Else Do3() : EndIfWunderlich
@Waiver yeah, but that's just splitting lines with colons, TRS-80 style. They are syntactically the same as separate lines. But having the whole if-else on one line is neato.Farquhar
You can do it without the : and without the endif.... Like this.... If a = b then DoThis() else DoThat. And that's it. This even works in vb6Predigest
D
7
  • Child namespaces are in scope after importing their parent. For exampe, rather than having to import System.IO or say System.IO.File to use the File class, you can just say IO.File. That's a simple example: there are places where the feature really comes in handy, and C# doesn't do it.
Dragonfly answered 19/9, 2008 at 14:13 Comment(1)
I just hate this feature since I get lost without looking at namespace in the beginning of the file... but still +1!Predominance
H
6

Unlike break in C languages in VB you can Exit or Continue the block you want to:

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
Hoiden answered 19/9, 2008 at 14:7 Comment(0)
G
6

Here's a funny one that I haven't seen; I know it works in VS 2008, at least:

If you accidentally end your VB line with a semicolon, because you've been doing too much C#, the semicolon is automatically removed. It's actually impossible (again, in VS 2008 at least) to accidentally end a VB line with a semicolon. Try it!

(It's not perfect; if you type the semicolon halfway through your final class name, it won't autocomplete the class name.)

Gerrigerrie answered 19/9, 2008 at 14:7 Comment(0)
E
5

When declaring an array in vb.net always use the "0 to xx" syntax.

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

It makes it very clear about the span of the array. Compare it with the equivalent

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

Even if you know that the second example consists of 10 elements, it just doesn't feel obvious. And I can't remember the number of times when I have seen code from a programmer who wanted the above but instead wrote

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

This is of course completely wrong. As b(10) creates an array of 11 bytes. And it can easily cause bugs as it looks correct to anyone who doesn't know what to look for.

The "0 to xx" syntax also works with the below

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

By using the full syntax you will also demonstrate to anyone who reads your code in the future that you knew what you were doing.

Em answered 19/9, 2008 at 14:7 Comment(5)
Horrors! the "to" keyword isn't capitalized! ;)Unalienable
VB.NET keywords are case insensitive actually. :) Not sure if that counts as a hidden feature.Theta
The fact that Dim b(9) as byte creates an array with 10 places drives me mad. I understand why Microsoft did it, but that doesn't mean it was a good decision (and I say this as someone who likes VB .NET). Of course, it's not as awful as it could be because for most things I use collections instead of arrays anyhow.Gerrigerrie
Vb.net array initializer counter is zero-based.Wunderlich
BTW, you can also include n To f Step x in case you want to dynamically generate an array according to some content.Wunderlich
W
5

You can use reserved keyword for properties and variable names if you surround the name with [ and ]

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
Waiver answered 19/9, 2008 at 14:7 Comment(3)
Consider that there are also keywords that are Like From Error and more that you might want to use it, I know it's rare, but there are always exceptions.Wunderlich
Ok, I take the liberty to edit the answer. Hope you don't mind.Edwards
This is a very useful thing to know, actually. Try typing this: Public Sub Stop It doesn't work, because Stop is a keyword. The brackets allow you to use Stop as your method name when it makes more sense than another name.Gerrigerrie
W
5
IIf(False, MsgBox("msg1"), MsgBox("msg2"))

What is the result? two message boxes!!!! This happens cuz the IIf function evaluates both parameters when reaching the function.

VB has a new If operator (just like C# ?: operator):

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

Will show only second msgbox.

in general I would recommend replacing all the IIFs in you vb code, unless you wanted it to evealueate both items:

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

you can be sure that both values were loaded.

Waiver answered 19/9, 2008 at 14:7 Comment(0)
P
5

Similar to Parsa's answer, the like operator has lots of things it can match on over and above simple wildcards. I nearly fell of my chair when reading the MSDN doco on it :-)

Paleozoology answered 19/9, 2008 at 14:7 Comment(0)
D
5

Select Case in place of multiple If/ElseIf/Else statements.

Assume simple geometry objects in this example:

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
Discard answered 19/9, 2008 at 14:7 Comment(7)
There is a switch in C#, and that is an abominationRochus
Haha, I've used this quite extensively, and my method became about 300 lines long in about 20 minutes.Predominance
I can't fathom what would make people think that Select Case True is better than a plain old If. If you're using it like an If, just make it an If. Why obfuscate?Gerrigerrie
@Kyralessa, I think it is the aesthetic of all of the conditions being indented the same. However another reason it occurs is when a Select Case Expression evolves and the Case Else becomes another large conditional.Woolworth
@Kyralessa, what if the types have nothing in common such as Int32, Date, and String? Polymorphism only works when you control over class's definitions.Astigmatic
What is REALLY important to understand regarding Select-Case is this: ANY time you have to add another case, you end up altering code that was already known to work and now have to test it completely again. Your code should always try following the Open-Closed-Principle: Open to extension, Closed to changes. Design your classes so that they can be extended without having to change their implementation. For example the strategy pattern can be used to refactor a Select-Case statement to something that allows you to follow the O/C principle.Reparation
@Mephisztoe: The same goes for a repetitive-looking if/else/else/else/... statement. What you're really saying here is write good smart code. yes, I agree with that.Farquhar
H
5

In VB8 and the former vesions, if you didn't specify any type for the variable you introduce, the Object type was automaticly detected. In VB9 (2008), the Dim would act like C#'s var keyword if the Option Infer is set to On (which is, by default)

Hoiden answered 19/9, 2008 at 14:7 Comment(3)
ALWAYS set Option Explicit. You can use Tools-Options to insert this automatically in all new source files.Pedicure
It's automatically set in the project properties by default, unless you're still working with VB 6 or olderHoiden
I believe it's actually Option Strict, not Option Explicit, which prevents you from typing Dim i and getting an Object type. It forces you to type As Object if you really want an object. Even with Option Infer on, it's best to have Option Strict (and Option Explicit) turned on as well.Gerrigerrie
C
4

The Nothing keyword can mean default(T) or null, depending on the context. You can exploit this to make a very interesting method:

'''<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
Counterfactual answered 19/9, 2008 at 14:7 Comment(1)
+1 for the nice hack but not terribly useful since .NET provides the same information by querying the GetType(T).IsValueType property.Dannica
W
4

Unlike in C#, in VB you can rely on the default values for non-nullable items:

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

Whereas in C#, this will be a compiler error:

int x;
var y = x.ToString(); //Use of unassigned value
Waiver answered 19/9, 2008 at 14:7 Comment(3)
No, actually you can't. Dim I as Integer is not always 0.Elata
@Elata can you provide any link to base what you said?Wunderlich
I just posted some code you can run. https://mcmap.net/q/16355/-strangest-language-feature/…Elata
H
4

MyClass keyword provides a way to refer to the class instance members as originally implemented, ignoring any derived class overrides.

Hoiden answered 19/9, 2008 at 14:7 Comment(0)
C
4

It is also important to remember that VB.NET projects, by default, have a root namespace that is part of the project’s properties. By default this root namespace will have the same name as the project. When using the Namespace block structure, Names are actually appended to that root namespace. For example: if the project is named MyProject, then we could declare a variable as:

Private obj As MyProject.MyNamespace.MyClass

To change the root namespace, use the Project -> Properties menu option. The root namespace can be cleared as well, meaning that all Namespace blocks become the root level for the code they contain.

Calebcaledonia answered 19/9, 2008 at 14:26 Comment(1)
This has bitten us in a few cases where we added further namespaces inside the project. In a few cases we have the "My" keyword under one of our namespaces; which makes finding Resources a pain until you realize where they've been moved to :)Ramsden
S
4

may be this link should help

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

Sash answered 13/10, 2008 at 16:12 Comment(1)
Cool, but mostly just GUI candy.Farquhar
H
3

VB also offers the OnError statement. But it's not much of use these days.

On Error Resume Next
' Or'
On Error GoTo someline

Hoiden answered 19/9, 2008 at 14:7 Comment(3)
@SungMeister, I like the power exceptions provide and do use them in new code, but for the (few) situations where On Error Resume Next is the right thing, it is much less cluttered than Try Catch on every statement.Woolworth
@Mark Hud: But sometimes limiting what one can use can discourage bad coding practices. I have seen too many ON ERROR RESUME NEXT or ON ERROR GOTO 1's when people are under time pressure. Leaving such a feature for the sake of very few specialized cases that can be solved through a bit verbose way, IMHO, cannot be justified. But Alas, it is for a backward compatibility purposes AFAIK.Predominance
@Sung Meister: yeah, but if they do, how will I quickly port all my awzzum old QuickBasic programs?Farquhar
C
3

Aliassing namespaces

Imports Lan = Langauge

Although not unique to VB.Net it is often forgotten when running into namespace conflicts.

Contra answered 19/9, 2008 at 14:26 Comment(1)
Can you do this declaritively as well?Triplicate
H
2

Nullable Dates! This is particularly useful in cases where you have data going in / coming out of a database (in this case, MSSQL Server). I have two procedures to give me a SmallDateTime parameter, populated with a value. One of them takes a plain old date and tests to see if there's any value in it, assigning a default date. The other version accepts a Nullable(Of Date) so that I can leave the date valueless, accepting whatever the default was from the stored procedure

<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
Hummel answered 19/9, 2008 at 14:7 Comment(1)
Along the same lines are nullable numbers!Voroshilovgrad
W
2
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

In this snippet you have 2 (maybe more?) things that you could never do in C#:

  1. Handles Button1.Click - attach a handler to the event externally!
  2. VB's implicitness allows you to declare the first param of the handler as the expexted type. in C# you cannot address a delegate to a different pattern, even it's the expected type.

Also, in C# you cannot use expected functionality on object - in C# you can dream about it (now they made the dynamic keyword, but it's far away from VB). In C#, if you will write (new object()).Enabled you will get an error that type object doesn't have a method 'Enabled'. Now, I am not the one who will recommend you if this is safe or not, the info is provided AS IS, do on your own, bus still, sometimes (like when working with COM objects) this is such a good thing. I personally always write (sender As Button) when the expected value is surely a button.

Actually moreover: take this example:

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
Waiver answered 19/9, 2008 at 14:7 Comment(3)
Your examples only work with Option Strict Off. And Option Strict Off is a Bad Thing, because it leads to runtime errors if you misspell the name of the late-bound members you're using.Gerrigerrie
Strict off is the advantage of VB. To each is own taste, every thing has it's own pros and cons.Wunderlich
@Kyralessa, While I usually with you, there are some amazing Function Programming techniques that can't do with option strict turned on. In fact, they are outright impossible in C# even with dynamic.Astigmatic
H
2

It's not possible to Explicitly implement interface members in VB, but it's possible to implement them with a different name.

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

Please vote for this feature at Microsoft Connect.

Hoiden answered 19/9, 2008 at 14:7 Comment(6)
I think you mean implicitlyAdmire
@Eric: No, explicitly implementing is a feature available in C# which makes the explicitly implemented method unavailable to instanced of the class directly and if you want to call them you must cast your class to the interface type. Take a look at msdn.microsoft.com/en-us/library/ms173157%28loband%29.aspxHoiden
@Jonathan Allen: Can't figure why?Hoiden
Consider IEnumerable.GetEnumerator and IEnumerable(Of T).GetEnumerator. If you expose the generic version, there is no reason to also expose the non-generic version.Astigmatic
Please vote for this feautre: connect.microsoft.com/VisualStudio/feedback/details/454529/…Wunderlich
@Jonthan it always freaks me out, anyway, if you declare them both as Overloads, it's possible.Wunderlich
C
2

I don't know how hidden you'd call it, but the If operator could count.

It's very similar, in a way, to the ?: (ternary) or the ?? operator in a lot of C-like languages. However, it's important to note that it does evaluate all of the parameters, so it's important to not pass in anything that may cause an exception (unless you want it to) or anything that may cause unintended side-effects.

Usage:

Dim result = If(condition, valueWhenTrue, valueWhenFalse)
Dim value = If(obj, valueWhenObjNull)
Colvin answered 19/9, 2008 at 14:10 Comment(10)
Also, it's return type is Object. I use my own typesafe IIf(Of T) implementation.Dragonfly
VB9 now has a If that is ternay operator just like the ?: in CEal
I see that. It makes me sad that I don't get to use VB9 at work right now.Colvin
@Rick: Really? What operator would that be?Equities
@Boo: Rick actually used the actual name of the new operator. It is "If" as opposed to "Iif" (one fewer "i"). The difference is that "Iif" evaluates all of its arguments but "If" evaluates just the ones it needs to.Saraann
@Sam Erwin: I've changed your original post for convenience.Wunderlich
@Pondidum: IIf is probably managed, and not only but it evaluates both operands (try IIf(False, MsgBox(False), MsgBox(True)) - it will show both messages), it should be deprecated and only the If operator should be used.Wunderlich
@Joel Coehoorn: The VB9 If operator is generic / type/safe!Wunderlich
@shimmy - I know that. At the time this post was written, it didn't mention that operator, VS 2008 was still pretty new, and the If operator effectively didn't exist yet to most programmers.Dragonfly
As it stands, this is now wrong. If does not evaluate all its parameters.Woolworth
B
2

You can use REM to comment out a line instead of ' . Not super useful, but helps important comments standout w/o using "!!!!!!!" or whatever.

Bettis answered 19/9, 2008 at 14:44 Comment(8)
Notice, however, that usage of REM is deprecated. The VB team is considering removing it from the next version altogether. Future-proof code is therefore better off not employing it.Dannica
True, but they haven't they been saying that since VB5?Lothario
I don't they will ever remove itWunderlich
Wow... REM... It's been awhile! I don't think I've used REM since the Apple ][cPeltate
@KonradRudolph @Oorang: Link please. Googling for 'vb.net REM "depreciated" site:microsoft.com' finds nothing.Woolworth
@Mark No link available (wayback machine might work) since the source of my information is Paul Vick’s blog (from when he headed the VB team), which he has since scrubbed.Dannica
@KonradRudolph: Google 'REM site:panopticoncentral.net' returns exactly one page where the Google cache shows Paul mention in a comment that REM "still works, even in VB.NET!"Woolworth
@Mark Then Google hasn’t indexed all pages, or the cache has dropped them. I’m certain that this was discussed on the site.Dannica
T
1

Documentation of code

''' <summary>
''' 
''' </summary>
''' <remarks></remarks>
Sub use_3Apostrophe()
End Sub
Tasman answered 19/9, 2008 at 14:7 Comment(0)
W
1

Differences between ByVal and ByRef keywords:

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
Wunderlich answered 19/9, 2008 at 14:7 Comment(3)
Except that, unfortunately, this doesn't work with collections - try passing a collection in ByVal and then removing an item from it in your sub - you'll find that it's been removed from the original as well :(Constitutive
It works with collection too. Because when you cange a collection, you don't change the instance itself, you just change the internal propetries of it. and if you want to see it yourself, try a method that has a ByVal param of c of type collection, set it to a new collection within the method, and you'll see that the argument doesn't contain your new collection outside the method scope, unlike when it's ByRef.Wunderlich
@rwmnau, collections are reference types. Whether you use ByVal or ByRef, you're pointing to the original collection. The difference is that if inside the method you point your variable to a different collection or to null, then when you return from the method, if you used ByVal you'll still be pointing to the original collection; but if you used ByRef you'll be pointing to the new collection or to null, whatever you reassigned to inside the method. TL;DR: Use ByRef as infrequently as possible. And if you need a copy of a collection, then explicitly copy it; ByRef doesn't do that.Gerrigerrie
H
1

Someday Basic users didn't introduce any variable. They introduced them just by using them. VB's Option Explicit was introduced just to make sure you wouldn't introduce any variable mistakenly by bad typing. You can always turn it to Off, experience the days we worked with Basic.

Hoiden answered 19/9, 2008 at 14:7 Comment(0)
D
1

I used to be very fond of optional function parameters, but I use them less now that I have to go back and forth between C# and VB a lot. When will C# support them? C++ and even C had them (of a sort)!

Dragonfly answered 19/9, 2008 at 14:19 Comment(5)
I was never a fan, but your answer prompted me to dig into them a bit and see what they looked like under the hood. You may be interested in [How do optional parameters work?][1] [1] #104568Kalat
Optional parameters and named parameters will be in the next version of C#.Jabe
although they are generally considered bad practice; use overloaded methods instead.Equidistant
Agreed on overloads, but you can't overload when you're doing COM Interop, so you have to use the optionals - and named parameters are vital when you're doing Interop into Office, where the methods have 30-40 optional parameters.Latterll
optional params are now supported in C#!Wunderlich
C
0

Optional arguments again !

Function DoSmtg(Optional a As string, b As Integer, c As String)
    'DoSmtg
End 

' Call
DoSmtg(,,"c argument")

DoSmtg(,"b argument")
Chart answered 19/9, 2008 at 14:7 Comment(0)
H
0

Attributes for methods! For example, a property which shouldn't be available during design time can be 1) hidden from the properties window, 2) not serialized (particularly annoying for user controls, or for controls which are loaded from a database):

<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

Putting in the DebuggerStepThrough() is also very helpful if you do any amount of debugging (note that you can still put a break-point within the function or whatever, but that you can't single-step through that function).

Also, the ability to put things in categories (e.g., "Data") means that, if you do want the property to show up in the properties tool-window, that particular property will show up in that category.

Hummel answered 19/9, 2008 at 14:7 Comment(0)
W
0
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
Waiver answered 19/9, 2008 at 14:7 Comment(0)
L
-3

The Me Keyword

The "Me" Keyword is unique in VB.Net. I know it is rather common but there is a difference between "Me" and the C# equivalent "this". The difference is "this" is read only and "Me" is not. This is valuable in constructors where you have an instance of a variable you want the variable being constructed to equal already as you can just set "Me = TheVariable" as opposed to C# where you would have to copy each field of the variable manually(which can be horrible if there are many fields and error prone). The C# workaround would be to do the assignment outside the constructor. Which means you now if the object is self-constructing to a complete object you now need another function.

Linguistician answered 19/9, 2008 at 14:7 Comment(2)
Yup, it'll give you a compile error - 'Me' cannot be the target of an assignmentRaft
Actually, this in C# is not always readonly; inside a struct it can be assigned. Maybe @Linguistician is referring to VB structs? Perhaps? Just possibly? Probably not, actually.Naturalize

© 2022 - 2024 — McMap. All rights reserved.