Assign Nothing to a Short variable in VB.NET - vb.net

I have a below line of code like this.
Private Sub SomeFunction(ByRef SomeShortVariable As Nullable(Of Short))
Dim SomeStringVariable As String = "" 'Let's assume it is "", that's how I am getting it in real time code
SomeShortVariable = IIf(SomeStringVariable = "", Nothing, SomeStringVariable) 'I want to set SomeShortVariable to Nothing but I am getting 0
End Sub
The variable SomeShortVariable is always sets to 0 even though I want it to be Nothing.
I know Short by default will set the variable to 0.
But how can I make it Nothing. I am using .NET 2.0.

Make SomeShortVariable a Nullable(Of Short) variable.
EDIT:
Also your statement should look like this:
SomeShortVariable = If(String.IsNullOrEmpty(SomeStringVariable), Nothing, New Nullable(Of Short)(Short.Parse(SomeStringVariable)))
SECOND EDIT:
If you're using Visual Studio 2005 the above won't work, because the If operator was only introduced in VS2008. So what you'll have to do is this:
If String.IsNullOrEmpty(SomeStringVariable) Then
SomeShortVariable = Nothing
Else
SomeShortVariable = Short.Parse(SomeStringVariable)
End If
Of course you will want to validate that SomeStringVariable is a numeric string first. :)

Regarding your update, well, that's cause it's Short, and not Nullable(Of Short) in the parameter. Make it nullable of Short and you are done. Although I would refactor to avoid ByRef, have a string parameter SomeStringVariable and return a Nullable(Of Short). Then things would start to make more sense.
Private Shared Function SomeFunction(SomeStringVariable As String) _
As Nullable(Of Short)
If String.IsNullOrEmpty(SomeStringVariable) Then
Return Nothing
Else
Return Convert.ToInt16(SomeStringVariable)
End If
End Function
EDIT: Actually shorthand syntax won't work in this case, for the reasons I outlined in my comment regarding change to If. Just don't use shorthand.

Watch out for the recommendations to use Convert or Parse on cases where the input string could be something other than an empty string but not a number (any user supplied input). It is typically better to use TryParse unless you are absolutely sure someone hasn't passed something in that you aren't expecting. Consider the following:
Dim someString = "a"
Dim someShort as new Nullable(Of Short)
Dim tempShort as Short
Console.WriteLine(someShort)
If Integer.TryParse(someString, tempShort) then
someShort = tempShort
end if
console.WriteLine(someShort)
if Not String.IsNullOrEmpty(someString) then
someShort = Short.Parse(someString) ' Throws FormatException
end if
Console.WriteLine(someShort)

Related

Dealing with Nothing in the middle of a string of calls

I am a relative VB.Net noob, and I'm learning by doing. I'm sure what I'm about to ask has been asked 10^19 times before, but whatever code word it's under, I can't figure out how to Google it. Here goes...
We have an object model with one or more Project objects that consists of several Tables, which contain Rows which have Fields. This leads to code all over our apps that looks something like this...
Dim theColor As String = Projects(1).Tables(5).Rows(22).Fields(3)
In our application, if any of the objects in this "call chain" does not exist, the correct value for theColor should be Nothing*. This is just like Excel - the value of an empty cell in an empty row is vbnull, not "Excel has crashed".
This is not how VB.Net works, however. If, for instance, Rows(22) does not exist, the Fields(3) is called on Nothing and an exception is thrown. My question is how to best deal with this...
1) I could check each value to see it it's not Nothing, but that leads to horrible amounts of code...
If Projects(1) IsNot Nothing AndAlso Projects(1).Tables(5) AndAlso...
We have thousands of these, the amount of code this would require would be enormous.
2) I could wrap all accessors in try/catch, but that's really just a different sort of (1)
3) I could have a special instance of each object that has empty values. So, for instance, Tables(5) returns NullTable and Row(22) returns NullRow. But this means I have to always use accessor methods, I can't just look in the underlying arrays. You're probably saying good, but sadly a lot of our older code does just that (yes, duh).
4) Something else entirely? Am I missing some magic that everyone other than me knows?
You could have a function called GetField
Instead of
Dim theColor As String = Projects(1).Tables(5).Rows(22).Fields(3)
You would have
Dim theColor As String = GetField(1, 5, 22, 3)
Function GetField(ByVal projectIndex As Integer, ByVal tableIndex As Integer, ByVal rowIndex As Integer, byVal fieldIndex As Integer) As Object
If Projects(projectIndex) Is Nothing Then
Return Nothing
End If
If Projects(projectIndex).Tables(tableIndex) Is Nothing Then
Return Nothing
End If
If Projects(projectIndex).Tables(tableIndex).Rows(rowIndex) Is Nothing Then
Return Nothing
End If
If Projects(projectIndex).Tables(tableIndex).Rows(rowIndex).fields(fieldIndex) Is Nothing Then
Return Nothing
End If
Return Projects(projectIndex).Tables(tableIndex).Rows(rowIndex).fields(fieldIndex)
End Function
But I got to say... what you are doing looks sloppy. You should think of using classes with properties.
You could concoct a "project manager" of sorts. It is hard to know how viable this is from the post, but something like:
Class ProjectManager
Public Property CurrentProject As ProjectThing
Public Property CurrentTable As Integer
Get
Return tblIndex
End Get
Set
If CurrentProject IsNot Nothing Then
If CurrentProject.Tables(value) Is Nothing Then
Throw exception
Else
tblIndex = value
End If
End If
End Set
End Property
' etc
Then use it to store the current reference to the project and/or table. All the Is Not Nothings can be embedded there.
Private myPrj As New ProjectManager
...
myPrj.CurrentProject = Project(1)
myPrj.CurrentTable = 5
With the "manager" doing all the checking for everyone, you dont have to (much):
Dim theColor As String = myPrj.Rows(22).Fields(3)
or
Dim theColor As String = myPrj.GetRowValue(22, 3)
What it would really be doing is storing a validated object references for you, and testing those not worth storing. It could go as deep as you needed. Even if all it really did was encapsulate those Is Nothing/Is Not Nothing tests, it might add some value.
Public Function GetRowValue(r As Integer, f as Integer) As Something
If r < CurrentProject.Tables(tblIndex).Rows.Count AndAlso
f < CurrentProject.Tables(tblIndex).Rows(r).Fields.Count Then
Return ...
'or
Public Function GetRowValue(Of T)(r As Integer, f as Integer) As T
Once a project is specified, it could expose helpful properties like TableCount. It is possible that the data represented by some of the most used, most important Const definitions, could be exposed as properties:
' swap a property interface for "3"
Dim theColor As String = myPrj.FooColor(22)
You can handle the exception:
Dim theColor As String = Nothing
Try
theColor = Projects(1).Tables(5).Rows(22).Fields(3)
Catch
End Try
If you want to do it 'properly' you should specify the exceptions you are guarding against:
Dim theColor As String = Nothing
Try
theColor = Projects(1).Tables(5).Rows(22).Fields(3)
Catch ex As IndexOutOfRangeException
Catch ex As NullReferenceException
End Try

vb.net Loop through public structure and pass to generics

I have inherited some god awful vb.net code and having trouble trying to work out the generics for looping through the current structure in place.
here is a snippet of the struct
Public Structure ApplicationDetails
Dim ID As Integer
Dim AgentID As Integer
Dim ApplicationDate As Date
Dim CompletedDate As Date
here is the madness to populate it
With ApplicationInfo
.ID = If(Not IsDBNull(DT(0)("ID")), DT(0)("ID"), Nothing)
.ApplicationDate = If(Not IsDBNull(DT(0)("ApplicationDate")), DT(0)("MortgageAmount"), Nothing)
.CompletedDate = If(Not IsDBNull(DT(0)("CompleteDate")), DT(0)("MortgageAmount"), Nothing)
now i want to do something like this:
For Each item In ApplicationInfo.GetType().GetProperties()
Dim thisType = item.GetType()
Dim name = item.Name
Dim value = DtItem(Of item.GetType())(0, name.ToString(), DT)
item.SetValue(item, value, Nothing)
Next
Private Function DtItem(Of T)(ByVal num As Integer, ByVal name As String, ByRef DT As DataTable) As T
Return If(Not IsDBNull(DT(num)(name)), DT(num)(name), Nothing)
End Function
but i am not sure on the syntax to set the value and when trying to get the type i get item.GetTYpe() is not declared. I know i must be on the right track, just missing a little something.
A number of issues.
First and foremost, SetValue only works on object types, not values, so you would have to change your Structure to a Class.
Public Class ApplicationDetails
End Class
Next, you are looping through properties but your "structure" only had fields. So you need to add properties:
Public Class ApplicationDetails
Private _ID As Integer
Property ID As Integer
Get
Return _ID
End Get
Set(ByVal value As Integer)
_ID = value
End Set
End Property
//' etc
End Class
Otherwise, you would have to work with GetFields.
I don't think Generics will work here since you are only dealing with objects and you don't know the type (despite reflection):
Private Function DtItem(ByVal num As Integer, ByVal name As String, ByRef DT As DataTable) As Object
Return If(Not IsDBNull(DT(num)(name)), DT(num)(name), Nothing)
End Function
Lastly, your reflection call is wrong. Try changing it to this:
For Each item As PropertyInfo In ApplicationInfo.GetType().GetProperties
Dim value As Object = DtItem(0, item.Name, _dt)
If item.CanWrite Then
item.SetValue(ApplicationInfo, value, Nothing)
End If
Next
I'm not sure doing this through reflection is gaining you anything. In your "madness" example, it looks like you might be trying to put in a MortgageAmount, which I assume is a decimal, into a date field. That might be needed to look at.
I think you need to rethink your functional decomposition there. You're not getting much out of moving one line into a function, and I don't think you'll be able to pass a type constructor to a generic the way you are attempting to do so. You're also confusing some of your type checks.
Try something along these lines instead:
For Each item In ApplicationInfo.GetType().GetProperties()
Dim theName As String = item.Name,
isNullable = Not item.PropertyType.IsValueType OrElse _
Nullable.GetUnderlyingType(item.PropertyType) IsNot Nothing
If item.CanWrite Then
If Not IsDBNull(DT(0)(theName))
item.SetValue(ApplicationInfo, DT(0)(theName), Nothing)
ElseIf isNullable
item.SetValue(ApplicationInfo, Nothing, Nothing)
End If
End If
Next
If your code is executed immediately after the object is initialized, the isNullable checks are extraneous and you could simply take no action as the properties will be initialized as null. Otherwise, I'd recommend performing the check so you don't attempt to assign Nothing to a value type, which is going to throw an exception. Alternatively, you could modify your structure to use nullable reference types, i.e.:
Public Structure ApplicationDetails
Property ID As Integer?
Property AgentID As Integer?
Property ApplicationDate As Date?
Property CompletedDate As Date?
End Structure
EDIT
As LarsTech points out, your structure members are not properties and this will not function as anticipated unless you modify your structure to indicate these fields are in fact properties, for which the compiler would automatically generate getters and setters.

ignore null reference exception vb.net

I am coding in vb.net.
At times the data is empty/null this is due to user's input into the db.
i will like to bypass it, however i get no luck.
here is snippet of my code:
If hct.mydbvalue.name IsNot Nothing Then
dr("mydbvalue") = hct.mydbvalue.name
End If
I still get an error:
System.NullReferenceException: Object reference not set to an instance of an object.
is there a way if it is a null value to not do anything?
Both #FishBasketGordo and #Yuck are correct, you need to check the full object path for nullability:
If (hct IsNot Nothing) AndAlso (hct.mydbvalue IsNot Nothing) AndAlso (hct.mydbvalue.name IsNot Nothing) Then
dr("mydbvalue") = hct.mydbvalue.name
End If
You won't get a NullReferenceException from data in the database that's null when using ADO.NET; ADO.NET uses DBNull.Value to represent null, so your null reference is coming from somewhere else. In the code above, your exception could occur if any of the following were null:
hct
hct.mydbvalue
dr
Make sure that the whole chain is not null. If hct or mydbvalue is null, you'll get the exception.
To me this looks like hct.mydbvalue is null, and therefore you can't call "name" on it.
Private Function NullCheck(ByVal inObject As Object, Optional ByVal defaultValue As Object = "") As Object
Dim out As Object
If Not IsDBNull(inObject) Then
out = inObject ' This returns the value that was passed in when it is not null
Else
out = defaultValue ' This ensures that out is something and defaults to ""
End If
Return out
End Function
You should be checking whether hct is Nothing, as well as mydbvalue. If you look at the exception message property, it will tell you which is causing the error.
I'm also solving this problem, but in C#.
On my project we've complex object paths like "RootObject.childObject.LitleObject.TinyObject.StringName"
when any of these objects in the path is null, you'll get a null reference when you try something easy like
if(RootObject.childObject.LitleObject.TinyObject.StringName == "a")
I would be okay if it just works as whole rest of the path will be null.
eg. when childObject = null, then I want also RootObject.childObject.LitleObject.TinyObject.StringName to be null, not null reference exception.
However I've found no solution yet, but there is one new operator which can slightly help you in some null tasks.
a = object.object ?? defaultValue;
operator ?? is something like ISNULL in SQL server. If object on left is null, it returns the object from right.
It also replaces whole function NullCheck posted by Michael above.
Hope this will help a bit.
more info on operators
http://msdn.microsoft.com/en-us/library/ms173224(v=vs.80).aspx
http://msdn.microsoft.com/en-us/library/6a71f45d(v=vs.80).aspx
you're talking about diferent things.
It doesn't matter if you use ISDBNull(x.y), String.IsNullOrEmpty(x.y) or (x.y=null)
The problem is far sooner than your selected function is called.
when X is null, it cannot have a property Y. so when you call
AnyOfYourPrefferedFunctions(x.y);
the error raises during evaluation of x.y (null. doesn't exist), so it stops before the machine actually knows what is the function you want to call.
Probably only way to check this, would be using reflection. But you would need to send string with path and reference to root. so something like:
var v = GetValueThroughReflection(rootObject, "rootObject.path.to.the.last.object");
Then you'll be able to write a function which will go through the object path and find which one is null and handle it accordingly. e.g. returns null.
But when you'll heavy use that function, it can make your application run slower. as you'll use reflection for such simple task as is getting value out of variable.
from VS14+ you can use
If hct?.mydbvalue?.name IsNot Nothing Then
dr("mydbvalue") = hct.mydbvalue.name
End If
Try inserting a IF NOT isdbnull(hct.mydbvalue.name)
The following code checks all values.
If hct IsNot Nothing AndAlso
hct.mydbvalue IsNot Nothing AndAlso
Not String.IsNullOrWhitespace(hct.mydbvalue.name) Then
dr("mydbvalue") = hct.mydbvalue.name
End If
Note that the last test used String.IsNullOrWhitespace(). I'm assuming name is a string and you don't want to save empty strings.
Update 1
The following code is a simple console application to prove that using IsDbNull() or Micheal's NullCheck() will throw NullReferenceException when hct.mydbvalue is Nothing.
Module Module1
Sub Main()
Dim hct = New hct
Dim dr = New Dictionary(Of String, String)
Dim errorCount = 0
Try
Dim thisCallWillFail = IsDBNull(hct.mydbvalue.name)
Catch ex As NullReferenceException
Console.WriteLine(
"Using IsDBNull() threw NullReferenceException as expected."
)
errorCount += 1
End Try
Try
Dim thisCallWillFail = NullCheck(hct.mydbvalue.name)
Catch ex As NullReferenceException
Console.WriteLine(
"Using NullCheck() threw NullReferenceException as expected."
)
errorCount += 1
End Try
Console.WriteLine("errorCount = 2? {0}", errorCount = 2)
End Sub
Private Function NullCheck(ByVal inObject As Object,
Optional ByVal defaultValue As Object = "") As Object
Dim out As Object
If Not IsDBNull(inObject) Then
' This returns the value that was passed in when it is not null
out = inObject
Else
' This ensures that out is something and defaults to ""
out = defaultValue
End If
Return out
End Function
End Module
Public Class hct
Property mydbvalue As mydbvalue
End Class
Public Class mydbvalue
Property name As String
End Class

VB.NET - If string contains "value1" or "value2"

I'm wondering how I can check if a string contains either "value1" or "value2"?
I tried this:
If strMyString.Contains("Something") Then
End if
This works, but this doesn't:
If strMyString.Contains("Something") or ("Something2") Then
End if
This gives me the error that conversion from string to Long can't be done.
If I put the or ("Something2") inside the parenthesis of the first one, it gives me the error that the string cannot be converted to Boolean.
So how can I check if the string contains either "string1" or "string2" without having to write too much code?
You have to do it like this:
If strMyString.Contains("Something") OrElse strMyString.Contains("Something2") Then
'[Put Code Here]
End if
You need this
If strMyString.Contains("Something") or strMyString.Contains("Something2") Then
'Code
End if
In addition to the answers already given it will be quicker if you use OrElse instead of Or because the second test is short circuited. This is especially true if you know that one string is more likely than the other in which case place this first:
If strMyString.Contains("Most Likely To Find") OrElse strMyString.Contains("Less Likely to Find") Then
'Code
End if
Here is the alternative solution to check whether a particular string contains some predefined string. It uses IndexOf Function:
'this is your string
Dim strMyString As String = "aaSomethingbb"
'if your string contains these strings
Dim TargetString1 As String = "Something"
Dim TargetString2 As String = "Something2"
If strMyString.IndexOf(TargetString1) <> -1 Or strMyString.IndexOf(TargetString2) <> -1 Then
End If
NOTE: This solution has been tested with Visual Studio 2010.
You have ("Something2") by itself - you need to test it so a boolean is returned:
If strMyString.Contains("Something") or strMyString.Contains("Something2") Then
If strMyString.Contains("Something") or strMyString.Contains("Something2") Then
End if
The error indicates that the compiler thinks you want to do a bitwise OR on a Boolean and a string. Which of course won't work.
If strMyString.Tostring.Contains("Something") or strMyString.Tostring.Contains("Something2") Then
End if
I've approached this in a different way. I've created a function which simply returns true or false..
Usage:
If FieldContains("A;B;C",MyFieldVariable,True|False) then
.. Do Something
End If
Public Function FieldContains(Searchfor As String, SearchField As String, AllowNulls As Boolean) As Boolean
If AllowNulls And Len(SearchField) = 0 Then Return True
For Each strSearchFor As String In Searchfor.Split(";")
If UCase(SearchField) = UCase(strSearchFor) Then
Return True
End If
Next
Return False
End Function
If you want to disregard whether the text is uppercase or lowercase, use this:
If strMyString.ToUpper.Contains("TEXT1") OrElse strMyString.ToUpper.Contains("TEXT2") Then
'Something
End if
Interestingly, this solution can break, but a workaround:
Looking for my database called KeyWorks.accdb which must exist:
Run this:
Dim strDataPath As String = GetSetting("KeyWorks", "dataPath", "01", "") 'get from registry
If Not strDataPath.Contains("KeyWorks.accdb") Then....etc.
If my database is named KeyWorksBB.accdb, the If statement will find this acceptable and exit the If statement because it did indeed find KeyWorks and accdb.
If I surround the If statement qualifier with single quotes like 'KeyWorks.accdb', it now looks for all the consecutive characters in order and would enter the If block because it did not match.

Hidden Features of VB.NET?

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
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?
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
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.
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*"
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)
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>
Object initialization is in there too!
Dim x as New MyClass With {.Prop1 = foo, .Prop2 = bar}
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?)
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)
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
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!
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#
AndAlso/OrElse logical operators
(EDIT: Learn more here: Should I always use the AndAlso and OrElse operators?)
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.
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
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.
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
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.
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
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
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")
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
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
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
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
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.)
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