.NET Framework - Best Way To Catch A NullException

Asked By Terranc on 11-Jun-07 08:25 AM
Hello, I was wondering if someone can give me a few pointers in catching an
exception correctly or at least making the code a little more elegant than
what I have. I have a rss reader that I built in VB. When I read the contents
from the xml file I create several labels controls that I place on the form
at runtime. My problem is that some rss feeds do not have a particular node
(in this case a "pubDate" for the publishing date of the feed) which causes
the application to throw a NullReferenceException. I've tried the following
code:

if nodeChannel("pubDate").InnerText = Nothing then ....

Unfortunately, this doesn't work when it comes to nulls. So, I currently
have the following code but I'm not happy with it:

Private Sub CreateControls()
title = New System.Windows.Forms.Label
rssLanguage = New System.Windows.Forms.Label
rssDescription = New System.Windows.Forms.Label
rssPubDate = New System.Windows.Forms.Label

Try
With title
.Name = "lblMyTitle"
.Text = nodeChannel("title").InnerText
.ForeColor = Color.Crimson
.SetBounds(47, 16, 53, 13)
End With

With rssLanguage
.Name = "lblRssLanguage"
.Text = nodeChannel("language").InnerText
.ForeColor = Color.Crimson
.SetBounds(194, 16, 39, 13)
End With

With rssDescription
.Name = "lblRssDescription"
.Text = nodeChannel("description").InnerText
.ForeColor = Color.Crimson
.SetBounds(75, 55, 500, 13)
End With

With rssPubDate
.Name = "lblPubDate"
.Text = nodeChannel("pubDate").InnerText
.ForeColor = Color.Crimson
.SetBounds(329, 16, 200, 13)
End With

Catch e As NullReferenceException
With rssPubDate
.Name = "lblPubDate"
.Text = "No publish date!"
.ForeColor = Color.Crimson
.SetBounds(329, 16, 200, 13)
End With
Finally
Dim linkFeed As New linkCreated(AddressOf CreateLink)
Me.Invoke(linkFeed, title, rssLanguage, rssDescription,
rssPubDate)
End Try
End Sub

As you can see when the exception occurs I'm assuming there's no pubDate in
the rss feed so I create a label saying No Publish Date. Is there a better
way in handling this. If so, please share you thoughts and ideas. I would
love to learn your methodology when you encounter issues such as mine. Thanks.
--
TC




Andrew Morton replied on 11-Jun-07 08:45 AM
Surely it is

If nodeChannel("pubDate").InnerText Is Nothing Then ....

?

Andrew
Terranc replied on 11-Jun-07 08:59 AM
The reason why the syntax:
if nodeChannel("pubDate").Innertext = Nothing

is not working is because the object isn't set to anything. Therefore, if
the object is nothing how can you compare Nothing to Nothing? Is there an
alternative?
--
TC
ManishBafn replied on 11-Jun-07 09:01 AM
Hi,
you can also try something like this:
if  node.InnerText.Length=0
node.InnerText = "blah blah";
else
node.InnerText ="Actual Text"

--
Hope this helps.
Thanks and Regards.
Manish Bafna.
MCP and MCTS.
Terranc replied on 11-Jun-07 09:03 AM
By the way the code
if nodeChannel("pubDate") is Nothing then...
does not work either. I tried this already before.
--
TC
DArnold replied on 11-Jun-07 09:39 AM
If it were me, I would be doing a null check first an avoid the
situation of the exception.

bBad = false

If nodeChannel("description").InnerText <> Nothing then
.Text = nodeChannel("description").InnerText
else
.Text = vbNullString
bBad = true
end if


if bBad then
message   'and whatever else you have to do
endif
\(O\)enone replied on 11-Jun-07 10:15 AM
By using the Is operator, as Andrew already said.

Internally an object that contains Nothing is actually a pointer with a
reference to NULL (zero). The "Is" operator allows you to compare two object
pointers. So if you have two form variables, for example, you could tell
whether they point to the same object instance (not two instances of the
same form but the actual same instance) by using the code:

\\\
If MyForm1 Is MyForm2 Then
...
End If
///

Note that this is not the same is using the = operator, which compares
values rather than references. Similarly you can use IsNot in VB2005 to
determine whether two object references are not the same instance, as
opposed to <> for values. (If you're using VS2003 or earlier, you need to
use the slightly more clumsy "If Not a Is b Then" syntax).

You can use this to determine whether an object set to Nothing (which has a
pointer to NULL) is Nothing (which also has a pointer to NULL) in the same
way.

Try putting this into your code prior to the line where your error occurs:

\\\
If nodeChannel Is Nothing Then
MsgBox("nodeChannel Is Nothing")
ElseIf nodeChannel("pubDate") Is Nothing Then
MsgBox("nodeChannel(""pubDate"") Is Nothing")
ElseIf nodeChannel("pubDate").InnerText Is Nothing Then
MsgBox("nodeChannel(""pubDate"".InnerText) Is Nothing")
Else
MsgBox("Type of InnerText is " &
TypeName(nodeChannel("pubDate").InnerText))
End If
///

Run that and see what it produces. (This assumes you're running in a
WinForms environment, if you're not you'll need to replace the MsgBox calls
with Debug.WriteLine or something else.)

--

(O)enone
Terranc replied on 11-Jun-07 10:17 AM
Thanks everyone for your input. I decided to look for the child node and if I
find the pubDate element I set a boolean variable to true; If I don't find
the pubDate element I set the boolean variable to false. I pass the boolean
value to a Sub routine and check whether it's true or false. If it's true I
process as normal if it's false I throw the execption which works for me. I
appreciate the everyone's comments and help.

The issue that I found was that the object didn't exist when I read an xml
file that didn't have the element which in turn makes it hard to compare
against the NOTHING value. For Example:

If I had a variable
Dim a as String
Then I tried to do the following:
if a.length = 0 then... this would cause the nullreferenceexecption because
a was never initialized. Well, my problem was similiar except I was using
elements straight from a xml file and if the element didn't exist then I
would get a runtime error.
--
TC
Andrew Morton replied on 11-Jun-07 10:18 AM
You don't use the = operator when checking for Nothing, you use the Is
operator.

However, are you saying that nodeChannel("pubDate") is the entity which is
nothing, or is it nodeChannel("pubDate").Innertext?

If the former, then what data type is nodeChannel and does that type have a
method for determining if a particular value of it exists?

Andrew
Kelly Ethridge replied on 11-Jun-07 11:37 AM
I think everyone is missing where your exception is being created from.
They seem to be assuming that the return value of the InnerText is
causing it. However, I will assume that you are trying to use an
XmlElement object returned from an XmlDocument (from what I can tell),
and directly calling the InnerText on that. I would create a simple
factory method to initialize each label with passed in arguments,
something similar to this:

Private Sub CreateControls()
title = CreateLabel("lblMyTitle", "title", "No title", 47, 16,
53, 13)
rssLanguage = CreateLabel("lblRssLanguage", "language", "No
language", 194, 16, 39, 13)
rssDescription = CreateLabel("lblRssDescription",
rssPubDate = CreateLabel("lblPubDate", "pubDate", "No publish
date!", 329, 16, 200, 13)

Dim linkFeed As New linkCreated(AddressOf CreateLink)
Me.Invoke(linkFeed, title, rssLanguage, rssDescription, rssPubDate)
End Sub

Private Function CreateLabel(ByVal name As String, ByVal nodeName As
String, ByVal errMsg As String, ByVal x As Integer, ByVal y As Integer,
ByVal w As Integer, ByVal h As Integer) As Label
Dim item As New System.Windows.Forms.Label

With item
.Name = name
.ForeColor = Color.Crimson
.SetBounds(x, y, w, h)

Dim node As XmlElement = nodeChannel(nodeName)
If node IsNot Nothing Then
.Text = node.InnerText
Else
.Text = errMsg
End If
End With

Return item
End Function
End Class

Kelly
AMDRIT replied on 11-Jun-07 12:01 PM
It seems to me that nodeChannel("pubDate") returns an object, and if this
object is nothing then any attempt to access it's members will fail with a
nullreference exception.

I would then:

dim pubDateFailed as boolean = true
dim sTemp as string

If nodeChannel("pubDate") is not nothing then
sTemp = nodeChannel("pubDate").innerText

if stemp is string.empty then
pubDateFailed = true
else
if isdate(pubDateFailed) then
pubDateFailed = false
else
pubDateFailed = true
end if
end if

else
pubDateFailed = true
end if

if pubDateFailed then
'throw out your exception logic
else
'populate accordingly
end if


And sense you are performing the same operation over and over again, you can
break the logic up.

private sub CreateControls()

title = New System.Windows.Forms.Label
rssLanguage = New System.Windows.Forms.Label
rssDescription = New System.Windows.Forms.Label
rssPubDate = New System.Windows.Forms.Label

try

SetControl(title, nodeChannel("title"), Color.Crimson, new Rectangle(47,
16, 53, 13), dataTypes.taString, "No title!")
...
SetControl(title, nodeChannel("pubDate"), Color.Crimson, new
Rectangle(329, 16, 200, 13), dataTypes.taString, "No publish date!")

Catch (e as exception)
'unhandled/unexpected exception logic here
finally
Dim linkFeed As New linkCreated(AddressOf CreateLink)
Me.Invoke(linkFeed, title, rssLanguage, rssDescription, rssPubDate)
end try

end sub

enum dataTypes
taString
taNumber
taDate
end enum

private sub SetControl(control as Label, name as string, node as object,
foreColor as Color, bounds as Rectangle, treatAs as dataTypes, nullValue as
string)

dim bFailed as boolean = true
dim sTemp as string

If node is not nothing then
sTemp = node.innerText

if stemp is string.empty then
bFailed = true
else

select case treatAs
case taString
bFailed = false
case taDate
if isdate(sTemp) then bFailed = false
case taNumber
is isNumeric(sTemp) then bFailed = False
end select
end if

else
bFailed = true
end if


With control
.Name = name

if bFailed then
.Text = nullValue
else
.Text = sTemp
end if

.ForeColor = forecolor
.SetBounds(bounds)
or
.SetBounds(bounds.x, bounds.y, bounds.height, bounds.width)

End With

end sub
Mr. Arnold replied on 11-Jun-07 12:48 PM
I don't know man. It seems to me that everything in .NET C# or VB is an
object. So, either it's an object or it's not an object.

I have read XML where the InnerText element was Null or  Nothing and the
code would have thrown the NullException had I not first checked asking it.
Are you an object or not an object?

I think the proper check is if InnerText <> Nothing.

You can do this little test yourself in code that should apply to your case.

dim strt as string

strt = "help"

if strt <> Nothing then
message (" I am an object.")
endif

strt = Nothing

if strt <> Nothing then
message ("I am an object.")
else
message ("I am not an object.")
endif

The same thing should apply to the XML you're working with of either it's an
object or it's not an object. I have used that in Case and IF statements  to
check the XML of being an object or not being an object.
Andrew Morton replied on 12-Jun-07 03:37 AM
No: see (O)enone's post in this thread as to why you have to use the "Is"
operator to check against Nothing.

Andrew
Mr. Arnold replied on 12-Jun-07 07:10 AM
No, I am sorry,  because I have used the Nothing keyword in both manners.

if Not InnerText is Nothing

and

If InnerText <> Nothing

They both are taking the same execution path of an object not being an
object or it is an object.

And I have tested this and it makes no difference about the above two
examples.

Nothing is a Null reference pointer, and an object is either an object with
a pointer to it or it's not an object with Null reference.
\(O\)enone replied on 12-Jun-07 09:25 AM
OK, then here are two things for you to try:

1. Turn Option Strict On in your source file (which I'd highly recommend at
all times). Suddenly the "=" and "<>" versions don't compile (Option Strict
requires you to use Is or IsNot instead)

2. With Option Strict switched back off again for a moment, try the
following:

\\\
Dim f As Object = New Form

If f Is Nothing Then
MsgBox("f is nothing")
End If
If f IsNot Nothing Then
MsgBox("f is not nothing")
End If
///

Execute it and unsurprisingly it'll tell you that "f is not nothing".

Now replace the "Is" with "=" and "IsNot" with "<>". Now when you execute
the code you get a run-time error:

Operator '=' is not defined for type 'Form' and 'Nothing'.

Trust me: use "Is" and "IsNot" for comparing object references, and "=" and

--

(O)enone
Mr. Arnold replied on 12-Jun-07 09:47 AM
There was no Option Strict prior to .Net 2005. With Option Strict off, which
is the default, this is really not applicable.


I appreciate your comments and I'll be aware of this, if I need Option
Strict ever enabled. I guess this has to be the reason IsNothing()
disappeared out of VB.NET 2.0
\(O\)enone replied on 12-Jun-07 10:11 AM
There definitely was in VS2003, and I'm pretty sure it was there in VS2002
too. Switching it on can save you from all sorts of errors that you
otherwise wouldn't spot until your code happens to hit a specific set of
conditions at run-time. And it might be your users that hit those conditions
before you do.

Personally I'd never write any code with Option Strict switched off. Up to
you though.


IsNothing is still there in VB.NET 2.0, in the
Microsoft.VisualBasic.Information namespace. (You'll obviously need a
reference to Microsoft.VisualBasic before you can use it, though). To me,
the syntax "If IsNothing(variable) Then" is much clumsier than "Is variable
Is Nothing Then" but again it's up to you.

HTH,

--

(O)enone
Mr. Arnold replied on 12-Jun-07 11:20 AM
I'll take your word for it. I never had to us it.




I'll keep it mind, the next time on a VB.net project.


I have used the  Microsoft.VisualBasic namespace, but not for this.

IsNothing() or Is Nothing as long as they work is the bottom line. I include
the <> in there as well as long Option Strict is off. :)

I came from a VB 6 background but have spent most of my .NET development in
C#, no Options.