Classes vs. Structures (Object reference not set to an instance of an object)

E

eBob.com

I am trying to change some Structures to Classes. The Classes now
look like this ...

Public Class OneAttr
Public AttrName As String
Public Column As String
Public Caption As String
End Class

Public Class OneTable
Public ObjectName As String
Public TableName As String
Public NextIndex As Integer = -1
Public Attrs() As OneAttr
End Class

Public Class Product
Public ProdCode As String
Public NextTableIndex As Integer = -1
Public AtTables() As OneTable
End Class

I made the change, by the way, because I could not do the
initialization of the two fields you see initialized above when I was
using Structures.

But now I get an "object reference not set to an instance of an
object" Many, many hits in Google (this seems to be .Net's favorite
error message) but none were helpful.

Here's the code ...

Dim ThisProd As New Product
ThisProd.NextTableIndex = -1
....

If line.IndexOf("*OBJECT: ") = 0 Then
ThisProd.NextTableIndex = _
ThisProd.NextTableIndex + 1
TI = ThisProd.NextTableIndex 'shorthand
InTable = True
ReDim Preserve ThisProd.AtTables(TI)
ThisProd.AtTables(TI).NextIndex = -1 '< Error
ThisProd.AtTables(TI).ObjectName = _
line.Substring(9).Trim(" "c)

The error occurs on the statement which reads:
ThisProd.AtTables(TI).NextIndex = -1

This code worked when I was using Structures. TI is 0, so I think
that I have created the 1st element of ThisProd.AtTables().

I'll appreciate any and all help, pointers, or sympathy.

Thanks, Bob
 
E

eBob.com

Well, it finally occurred to me that I should add Redim and Class to
my Google search. And one of the hits I got suggested to me that
maybe I should add this statement ...
ThisProd.AtTables(TI) = New OneTable
following the Redim. That does seem to have fixed the problem. But I
sure don't see why this statement should be needed when I use a Class
and not needed when I use a Structure.

Can anyone explain?

Thanks, Bob
 
G

Guest

Bob,

This is because a struct is a value type and a class is a reference type.
When you say...

DIM myStruct AS myStructType

....You are creating a structure on the heap, like saying ...

DIM myString AS string.

If you DIM something as a class you are actually creating a reference to
that type of object, not creating the object itself. The object is not
actualy created until NEW is encountered. So...

DIM myClass AS myObjectType

.... Does not create an object. In this case myClass will just be a null
pointer, of the correct type. When you say...

DIM myClass AS NEW myObjectType

.... you create a pointer called myClass that referes to a new object of
myObjectType.

Hope that helps,

Dan.
 
L

Larry Lard

eBob.com said:
Well, it finally occurred to me that I should add Redim and Class to
my Google search. And one of the hits I got suggested to me that
maybe I should add this statement ...
ThisProd.AtTables(TI) = New OneTable
following the Redim. That does seem to have fixed the problem. But I
sure don't see why this statement should be needed when I use a Class
and not needed when I use a Structure.

Can anyone explain?

I'll have a go :)

Basically a Structure is a value type, and a Class is an object type.
Dry definitions don't help much, so I'll try and elucidate:

When you have a variable of type <some value type>, eg an Integer or a
Point (a structure), that variable always _has a value_. For example,
even if you haven't explicitly set an integer variable to a value, it
already has a value (zero). Same with a variable of type Point. Code
snippet:

Dim i As Integer
If i=0 Then
'this will happen
End If

Dim p As Point
If p.X=0 Then
'this will happen
End If


OK now let's consider variables of type <some object type>, usually
called object variables. Such variables are actually _references to_ an
object; you might like to think of then as signposts; and importantly
they can _refer to no object_, or Nothing in VB.NET syntax. Like a
blank signpost, if you will. And until you explicitly set them to point
at _something_, Nothing is what they point to! Code snippet:

Dim o As Object
If o.GetHashCode()=0 Then 'ERROR!

We get an error because o doesn't refer to any object, so we have
nothing to get the hashcode of! The error we get is in fact 'object
reference not set to an instance of an object', and the reason it's so
common is that uninitialised object variables are a common problem :)

So let's see why you got an error when you switched from Structures to
Classes:

When OneTable is a Structure (a value type), then each entry in
AtTables is an actual OneTable value - possibly a blank value, but
always a value. When OneTable is a Class, then AtTables is a collection
of _references_, which are references to nothing, until you set them.

So when you get a new line and you want to add a new OneTable:

This is fine; we have made room for an extra reference

The error is because .AtTables(TI) is a null reference, until you make
it refer to something. When OneTable was a Structure, the ReDim
automatically created a new blank _value_; now it is creating a new
_null reference_. As you've discovered, the fix is to do

ThisProd.AtTables(TI) = New OneTable

after the ReDim. Now the reference refers to something, so you can use
it :)

There's probably a much better explanation of value types vs object
types in the MSDN somewhere, but hopefully this will get you started.
 
E

eBob.com

Thanks to the several responders. I sorta had a vague notion of the problem
but was unable to crystallize it. Thanks, Bob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top