Click here to Skip to main content
12,450,977 members (25,282 online)
Click here to Skip to main content
Add your own
alternative version

Stats

82.8K views
89 downloads
26 bookmarked
Posted

NullSafe Functions: Ensuring Safe Variables

, 7 Nov 2004
Rate this:
Please Sign up or sign in to vote.
In this article Rob Walling offers some functions that ensure variables returned from DataSets, ViewState, Session State, or Functions won't break your code.

Introduction

Values retrieved from DataSets, ViewState, Session State, or any number of other storage mechanisms can cause errors if they comes back as DBNull or Nothing. As an example, let's say you want to retrieve a String from a DataSet. Typically, you begin by checking if the value is DBNull.Value, then casting the value to a String (if you code with Option Strict On), then checking if it's Nothing, then trimming it. A similar process applies when retrieving a String from ViewState and Session State:

Dim firstName as string
' Check for DBNull
If ds.Tables(0).Rows("FirstName") is DBNull.Value Then
    firstName = String.Empty
Else
    firstName = CStr(ds.Tables(0).Rows("FirstName"))
    ' Check for Nothing
    If Not IsNothing(firstName) Then
        firstName = firstName.Trim
    End If
End If
' Now you can safely work with the value...

To overcome this cumbersome and repetitive process, I've created several "NullSafe" functions that handle the casting, trimming, and safety-checking of values.

Making Strings NullSafe

The first function is called NullSafeString. Notice that if the arg is DBNull, Nothing or String.Empty, the function defaults to returning an empty string, but you can override this behavior by passing a String of your choice as the second parameter:

'****************************************************************
' NullSafeString
'****************************************************************
Public Shared Function NullSafeString(ByVal arg As Object, _
Optional ByVal returnIfEmpty As String = "") As String

  Dim returnValue As String

  If (arg Is DBNull.Value) OrElse (arg Is Nothing) _
                   OrElse (arg Is String.Empty) Then
    returnValue = returnIfEmpty
  Else
    Try
      returnValue = CStr(arg).Trim
    Catch
      returnValue = returnIfEmpty
    End Try

  End If

  Return returnValue

End Function

Using the above function which resides in my Utility class, the code to pull FirstName from the DataSet becomes:

Dim firstName as string = _
    Utility.NullSafeString(ds.Tables(0).Rows("FirstName"), "Not Available")

This function guarantees that the value of firstName is safe to work with. In other words, method calls like firstName.Length, firstName.Replace will not throw exceptions.

Integers, Doubles, and Booleans

To ensure a value is strongly-typed upon its return from the NullSafe function, I create a new method for each data type. On most projects, I have four NullSafe methods, but on a few, I've had to extend to six to encompass Longs and Shorts. Below are my NullSafeInteger, NullSafeDouble, and NullSafeBoolean methods. You'll notice the default return value for the numeric functions is WILDCARD_ID, a constant I create with a value of -1. In the calling code, I can then check for this constant value to determine if the value is "valid."

'****************************************************************
' NullSafeInteger
'****************************************************************
Public Shared Function NullSafeInteger(ByVal arg As Object, _
  Optional ByVal returnIfEmpty As Integer = Constants.WILDCARD_ID) As Integer

  Dim returnValue As Integer

  If (arg Is DBNull.Value) OrElse (arg Is Nothing) _
                   OrElse (arg Is String.Empty) Then
    returnValue = returnIfEmpty
  Else
    Try
      returnValue = CInt(arg)
    Catch
      returnValue = returnIfEmpty
    End Try
  End If

  Return returnValue

End Function

'****************************************************************
'   NullSafeDouble
'****************************************************************
Public Shared Function NullSafeDouble(ByVal arg As Object, _
  Optional ByVal returnIfEmpty As Integer = Constants.WILDCARD_ID) As Double

  Dim returnValue As Double

  If (arg Is DBNull.Value) OrElse (arg Is Nothing) _
                   OrElse (arg Is String.Empty) Then
    returnValue = returnIfEmpty
  Else
    Try
      returnValue = CDbl(arg)
    Catch
      returnValue = returnIfEmpty
    End Try
  End If

  Return returnValue

End Function

'****************************************************************
' NullSafeBoolean
'****************************************************************
Public Shared Function NullSafeBoolean(ByVal arg As Object) As Boolean

  Dim returnValue As Boolean

  If (arg Is DBNull.Value) OrElse (arg Is Nothing) _
                   OrElse (arg Is String.Empty) Then
    returnValue = False
  Else
    Try
      returnValue = CBool(arg)
    Catch
      returnValue = False
    End Try
  End If

  Return returnValue

End Function

Conclusion

There is nothing magical about these functions; they simply encapsulate repetitive and cumbersome code into easy to use functions. Best of luck putting them to use!

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

rwalling
United States United States
No Biography provided

You may also be interested in...

Pro
Pro

Comments and Discussions

 
GeneralThis can be much simpler Pin
Sébastien Lorion7-Nov-04 19:27
memberSébastien Lorion7-Nov-04 19:27 
GeneralAlso ... Pin
Sébastien Lorion7-Nov-04 19:40
memberSébastien Lorion7-Nov-04 19:40 
GeneralRe: This can be much simpler Pin
rwalling9-Nov-04 19:13
memberrwalling9-Nov-04 19:13 
GeneralRe: This can be much simpler Pin
Sébastien Lorion9-Nov-04 22:25
memberSébastien Lorion9-Nov-04 22:25 
GeneralRe: This can be much simpler Pin
rwalling11-Nov-04 18:01
memberrwalling11-Nov-04 18:01 
GeneralRe: This can be much simpler Pin
Anonymous2-Feb-05 14:31
sussAnonymous2-Feb-05 14:31 
GeneralRe: This can be much simpler Pin
Anonymous2-Feb-05 18:08
sussAnonymous2-Feb-05 18:08 
GeneralRe: This can be much simpler Pin
robhughadams2-Nov-07 5:24
memberrobhughadams2-Nov-07 5:24 
Sadly point 1 isn't correct:
Sébastien Lorion wrote:
1.

To call the value type version of NVL, the internal type of the value argument must be a value type (ie the boxed type) AND the type of the emptyValue argument must also be a value type.


Dim o As Object

o = 1
NVL(o, 1) 'Call to value type version

o = "asdf"
NVL(o, 1) 'Call to object version

NVL(DBNull.Value, 1) 'Call to value type version
NVL(DBNull.Value, "asdf") 'Call to object value


The overload resolution is done at compile type and uses the type as declared, not the type of the object that is currently assigned to that variable.

You can see this if you change the test function to:
Private Sub TestNVL()
    Dim o As Object = DBNull.Value
    Debug.Write("NVL values :     ")
    Debug.Write(NVL(o, "test1"))
    Debug.Write(", ")
    Debug.Write(NVL(o, 1))
    Debug.Write(", ")
    o = Nothing
    Debug.Write(NVL(o, "test2"))
    Debug.Write(", ")
    o = "val"
    Debug.Write(NVL(o, "test3"))
    Debug.Write(", ")
    o = 1234
    Debug.Write(NVL(o, 3))
    Debug.Write(", ")
    o = New Decimal(123.345)
    Debug.WriteLine(NVL(o, 4))
    Debug.WriteLine("Correct values : test1, 1, test2, val, 1234, 123.345")
End Sub
Which produces this instead of the expected values:
NVL values :     , , , val, 1234, 123.345
More importantly if you attempt to cast the result instead of calling .ToString on it (which Debug.WriteLine does) an exception will be raised as the following proves:
Private Sub TestNVL()
    Dim o As Object = DBNull.Value
    Debug.Write("NVL values :     ")
    Dim s As String = DirectCast(NVL(o, "test"), String)
    Debug.Write(NVL(s, "test"))
    Debug.WriteLine("Correct value : test")
End Sub
So the NVL function will only work as expected if the input values have already been cast to the correct type - which defeats its purpose!

GeneralRe: This can be much simpler Pin
Matthew D3-Feb-05 7:06
memberMatthew D3-Feb-05 7:06 
GeneralRe: This can be much simpler Pin
Sébastien Lorion3-Feb-05 7:28
memberSébastien Lorion3-Feb-05 7:28 
GeneralRe: This can be much simpler Pin
Matthew D3-Feb-05 7:54
memberMatthew D3-Feb-05 7:54 
GeneralRe: This can be much simpler Pin
Sébastien Lorion3-Feb-05 8:10
memberSébastien Lorion3-Feb-05 8:10 
GeneralRe: This can be much simpler Pin
Matthew D3-Feb-05 8:20
memberMatthew D3-Feb-05 8:20 
GeneralRe: This can be much simpler Pin
Sébastien Lorion3-Feb-05 8:51
memberSébastien Lorion3-Feb-05 8:51 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160826.1 | Last Updated 7 Nov 2004
Article Copyright 2004 by rwalling
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid