Solved

Object reference not set to an instance of an object

Posted on 2010-08-16
11
553 Views
Last Modified: 2013-11-27
Hey All,

I have a wee bit of a problem.  Let me start by explaining the goal of this code.  The goal is to fill a pair DataGridViews (pOrders and cOrders) in one of my forms with information from a database.  Simple.

But I am running into a problem.  Suprisingly, I have not even gotten to the point of putting data into the GridView.  My problem is occuring when I am trying to fill the Generic.List(Of SomeType) with data that I get the error message.  I have looked at the scope to make sure that the issue is not there (made the object reference public and so forth).  Below is the code I have.  I would be grateful for any assistance that can be provided.

The error itself takes place in the RefreshPendingOrders and RefreshCompletedOrders Subs.  When I try to add a new OrderItemDetail to the Generic.List(Of OrderItemDetail), I recieve the error 'Object reference not set to an instance of an object'

Again, thanks for any assistance provided.

-saige-
Imports CCRS.Global.Settings.My
Imports CCRS.Global.Settings.My.Resources

Public Class Record
	Private ActiveCustomerID As Integer
	Private AllowCustomerEdit As Boolean
	Private SessionPayments As Generic.List(Of PaymentItem)
	Private pList As Generic.List(Of OrderDetailItem)
	Private cList As Generic.List(Of OrderDetailItem)

	Public Sub ViewCustomerRecord(ByVal customerID As Integer, ByVal allowEdit As Boolean)
		' ----- Provide access to the customer record.
		ActiveCustomerID = customerID
		AllowCustomerEdit = allowEdit
		Me.ShowDialog()
	End Sub

	Private Sub CustomerRecord_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown
		' ----- F1 shows online help.
		If (e.KeyCode = Keys.F1) Then OnlineHelp(Me, "CustomerRecord.htm")
	End Sub

	Private Sub RefreshPendingOrders(ByVal sqlText As String, _
	 ByVal dbInfo As SqlClient.SqlDataReader)
		Dim newEntry As OrderDetailItem

		On Error GoTo ErrorHandler

		' ----- Load in the list of pending orders.
		sqlText = String.Format("SELECT ID, Linker, RecordID, oNumber, oDate, " & _
		 "oTime, PONumber, Completed FROM Orders WHERE RecordID = {0} AND Linker = {1} AND " & _
		 "Completed = 0 ORDER BY oNumber", _
		 ActiveCustomerID, _
		 CInt(General.Linker.Customers))
		dbInfo = CreateReader(sqlText)
		Do While dbInfo.Read
			' ----- Add this order to the list.
			newEntry = New OrderDetailItem
			newEntry.ID = CInt(dbInfo!ID)
			newEntry.oNumber = DBGetText(dbInfo!oNumber)
			newEntry.oDate = CDate(dbInfo!oDate)
			newEntry.oTime = CDate(dbInfo!oTime)
			' Error occurs at this line - Object reference not set to an instance of an object
			pList.Add(newEntry)
		Loop
		dbInfo.Close()

		pOrders.DataSource = pList

ErrorHandler:
		GeneralError("CustomerRecord.RefreshPendingOrders", Err.GetException())
		If Not (dbInfo Is Nothing) Then dbInfo.Close() : dbInfo = Nothing
		Return
	End Sub

	Private Sub RefreshCompletedOrders(ByVal sqlText As String, _
	 ByVal dbInfo As SqlClient.SqlDataReader)
		Dim newEntry As OrderDetailItem

		On Error GoTo ErrorHandler

		' ----- Load in the list of completed orders.
		sqlText = String.Format("SELECT ID, Linker, RecordID, oNumber, oDate, " & _
		 "oTime, PONumber FROM Orders WHERE RecordID = {0} AND Linker = {1} AND " & _
		 "Completed = 1 ORDER BY oNumber", _
		 ActiveCustomerID, _
		 CInt(General.Linker.Customers))
		dbInfo = CreateReader(sqlText)
		Do While dbInfo.Read
			' ----- Add this order to the list.
			newEntry = New OrderDetailItem
			newEntry.ID = CInt(dbInfo!ID)
			newEntry.oNumber = DBGetText(dbInfo!oNumber)
			newEntry.oDate = CDate(dbInfo!oDate)
			newEntry.oTime = CDate(dbInfo!oTime)
			' Error occurs at this line - Object reference not set to an instance of an object
			cList.Add(newEntry)
		Loop
		dbInfo.Close()

		cOrders.DataSource = cList

ErrorHandler:
		GeneralError("CustomerRecord.RefreshCompletedOrders", Err.GetException())
		If Not (dbInfo Is Nothing) Then dbInfo.Close() : dbInfo = Nothing
		Return
	End Sub

	Private Sub CustomerRecord_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
		' ----- Prepare the form.
		Dim sqlText As String
		Dim dbInfo As SqlClient.SqlDataReader
		Dim holdText As String
		Dim counter As Integer
		Dim itemID As Integer
		Dim totalCount As Integer
		Dim totalAhead As Integer
		Dim canvas As Drawing.Graphics
		Dim newEntry As OrderDetailItem

		On Error GoTo ErrorHandler

		RecordLastActivity.Text = "Not Available"

		' ----- Load in the customer name. 
		sqlText = String.Format("SELECT C.ID, C.Active, C.LastName, C.MI, " & _
		 "C.FirstName, C.SuffixID, C.SAddressID, C.BAddressID, C.PhoneID, " & _
		 "C.GroupID, C.PTermID, C.Comments, C.AdminMessage, C.LastActivity, " & _
		 "S.ID, S.FullName FROM Customers As C " & _
		 "INNER JOIN CodeNameSuffix As S ON S.ID = C.SuffixID " & _
		 "WHERE C.ID = {0}", _
		 ActiveCustomerID)
		dbInfo = CreateReader(sqlText)

		If (dbInfo.Read) Then
			CustomerName.Text = FormatCustomerName(dbInfo)
			If (IsDBNull(dbInfo!LastActivity) = False) Then _
			 RecordLastActivity.Text = Format(CDate(dbInfo!LastActivity), _
			 "MMMM d, yyyy")
		End If
		dbInfo.Close()

		' ----- Load in the list of pending orders.
		RefreshPendingOrders(sqlText, dbInfo)

		' ----- Load in the list of completed orders.
		RefreshCompletedOrders(sqlText, dbInfo)

		' ----- If the user has authorization, show the Edit Customer button.
		If (SecurityProfile(CCRSSecurity.ManageCustomers) = True) Then
			' ----- If this form was called ultimately from the edit customer form,
			'       then hide the Edit Patron button.
			ActEditCustomer.Visible = AllowCustomerEdit
		Else
			' ----- This user is not authorized to edit customer records.
			ActEditCustomer.Visible = False
		End If

		Return

ErrorHandler:
		GeneralError("CustomerRecord.CustomerRecord_Load", Err.GetException())
		Resume Next
	End Sub

	Private Sub ActClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ActClose.Click
		' ----- Print out a ticket if needed.
		If (SessionPayments.Count > 0) Then _
		   PrintPaymentTicket(ActiveCustomerID, SessionPayments)
		SessionPayments.Clear()
		SessionPayments = Nothing

		' ----- Close the form.
		Me.DialogResult = Windows.Forms.DialogResult.Cancel
	End Sub
End Class

Open in new window

0
Comment
Question by:it_saige
  • 5
  • 4
  • 2
11 Comments
 
LVL 3

Accepted Solution

by:
with earned 500 total points
ID: 33450656
Hi saige,

Try changing lines 8 and 9 of what you posted to include the New keyword,
Private pList As New Generic.List(Of OrderDetailItem)
Private cList As New Generic.List(Of OrderDetailItem)

Open in new window

0
 
LVL 17

Expert Comment

by:nepaluz
ID: 33450674
How do you declare your Generic.List(Of OrderItemDetail)?
Since you do not include the declaration, my first port of call would be to make sure thatit is as below:

Dim YourList As New List(Of OrderItemDetail)

The NEW is rather important, the lack of which WILL throw an error like yours.
0
 
LVL 33

Author Comment

by:it_saige
ID: 33455805
Ok I used the New keyword in both of my declarations and viola, the data is now put into the lists.  I guess I still don't completely understand when to designate the New keyword.  :(

Thanks for your help.

-saige-
0
How our DevOps Teams Maximize Uptime

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us. Read the use case whitepaper.

 
LVL 3

Expert Comment

by:with
ID: 33455942
When you Dim an object type in VB.NET, think of that variable as being something that "could" point to an object in memory, but one that does not point to anything *yet*.  It does not yet "reference" an actual object in memory.

Btw, that's why the error message is, "Object reference" (i.e., your variable pList is the "reference") "not set to an instance of an object".  That's the compilers way of telling you, "hey, I went up to pList in memory but... nothing was there!?"

The New keyword is your way of constructing a "new" (hence the name) tangible, real List object in memory; the list is empty of items of course, but the List's "Add" method and soforth are now available via the pList reference variable.  

Prior to using the New keyword, pList knows what *Type* of object it could point at (List(Of T)), but prior to using the New keyword it doesn't point to a real one yet.
0
 
LVL 33

Author Comment

by:it_saige
ID: 33457059
Interesting...  Makes more sense now...

However, its funny how sometimes you get the reference methods without specifying new but only to find out at runtime that the object reference is invalid...

At other times, during the code writing intellisense lets you know that the object reference is invalid...

And yet still, you can have compile time errors that the object reference is invalid...

In my particular case, I was getting nothing during the writing or compile time with regards to the objects reference (from my point of view, I declared and referenced the object fine)...  It was only during runtime when the method was called that the object reference error occured (thank god for error trapping ;) )...

Do you have any articles or best practices that can be used or reference with regards to using the New Keyword (most of the time, I depend upon intellisense to let me know when I need to use the New keyword), but I would rather like to *know* without depending upon intellisense.

Thanks,

-saige-
0
 
LVL 17

Expert Comment

by:nepaluz
ID: 33457158
you can set up the types of warnings you need from the project properties - compile page.
If you have disable all warnings checked, then the compiler will happily follow your intructions.....
0
 
LVL 33

Author Comment

by:it_saige
ID: 33457425
I do not have disable all warning checked.  I *want* to know when errors occur. ;)

-saige-
0
 
LVL 3

Expert Comment

by:with
ID: 33457508
Yea, I don't like to disable warnings either :)

The compiler is pretty smart, but typically it's intelligence is confined to a certain scope, like a single Sub or a Function.  For example,

Sub MySub
    Dim myList List(Of Integer)
    myList.Add(1)
End Sub

Here I've failed to use New, so "myList" is an "object reference not set to an instance of an object".  To the compiler, it's pretty obvious this code will break. It can see that myList was defined inside MySub, so logically no other Sub or Function can access myList directly.  Therefor it's not possible for any external code to make myList New prior to the myList.Add attempt.

Your post was a just slightly more complex because you're using List objects defined *outside* the scope of the Subs they're used in.  Things just got a lot more complicated for the compiler because any Sub or Function in the Class *could* use the New keyword (or the opposite - set it back to Nothing!) so these variables when used in a Sub "could be anything", as far as the compiler is concerned.  So when things get to complicated, PlanB for the compiler is to give you the benefit of the doubt, and leave you alone.

A basic understanding of how "reference types" work should lead to an intuitive understanding of when to use the New keyword.  Unfortunately I don't have any good articles :\  If you Google around or start a question, what you want is a good VB.NET tutorial explaining Reference Types vs. Value Types.
0
 
LVL 33

Author Comment

by:it_saige
ID: 33457681
I think I get it now...

For my understanding.  If, lets say, I would have passed the list to the Sub or Function in question, the Sub or Function in question would depend upon the declaration of the object specified in the class in order to use the object.  As far as the compiler would then be concerned the Class would then need to instansiate the object with the new keyword and the compiler would then spit out a message with regards to that fact.  However, since I did not pass the list to the sub or function the compiler now says that my use of the object is depended upon my instansiation of the object within the sub or function or even outside of the sub or function by way of another method that instansiates the object.

As far as the compiler or intellisense is concerned, I have declared everything correctly because I could always rescope the object to a child method.  Am I following you correctly?

-saige-

0
 
LVL 3

Expert Comment

by:with
ID: 33458938
That's about right, maybe just overestimating the compiler's ability to read your code a little bit now.  Passing the reference won't improve the compilers knowledge in regards to whether or not the object has been instantiated yet.  The reason for that kinda starts to wade into the deep end of the swamp.  When it comes to null ref warnings, the design-time compiler can't see anything that happens outside the scope of an individual method; it just assumes that anything being passed in was (at some point) New'd up somewhere outside the scope of the method.

Btw I should mention it's perfectly normal, particularly in larger orthogonal systems, to simply ask what you're dealing with before you touch it:

If pList Is Nothing Then
   pList = New List(Of Things)
End If

So it either already was New'd, or, I just New'd it.  Either way, it's New'd.

pList.Add(aThing)

Experiment in a throw away project; make a list, pass it somewhere, make another list, set them equal to each other, add/remove things from the lists and check them both out.  That's another good way to pick up on a lot of this if you're the learn-by-doing type.
0
 
LVL 33

Author Comment

by:it_saige
ID: 33459084
> Experiment in a throw away project; make a list, pass it somewhere, make another list, set them equal to each other, add/remove things from the lists and check them both out.  That's another good way to pick up on a lot of this if you're the learn-by-doing type.

Why whatever gave you that idea...  :P

Learn by doing has always served me well...  You make more mistakes than the average bear, but you learn more about how and why things work...  The down side of the Learn by doing method is that you don't always produce the most elegant or most efficient code...

-saige-

0

Featured Post

The New “Normal” in Modern Enterprise Operations

DevOps for the modern enterprise offers many benefits — increased agility, productivity, and more, but digital transformation isn’t easy, especially if you’re not addressing the right issues. Register for the webinar to dive into the “new normal” for enterprise modern ops.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Does the idea of dealing with bits scare or confuse you? Does it seem like a waste of time in an age where we all have terabytes of storage? If so, you're missing out on one of the core tools in every professional programmer's toolbox. Learn how to …
A short article about problems I had with the new location API and permissions in Marshmallow
In this fourth video of the Xpdf series, we discuss and demonstrate the PDFinfo utility, which retrieves the contents of a PDF's Info Dictionary, as well as some other information, including the page count. We show how to isolate the page count in a…

840 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question