Author Topic: Variable not set to object - why?  (Read 2783 times)

0 Members and 1 Guest are viewing this topic.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Variable not set to object - why?
« on: November 16, 2009, 12:54:31 PM »
I have designed a private collection to hold filter values. This collection is simply a bunch of class objects that hold other data .... it is built from reading a file, as shown below.

Code: [Select]
Public Class Utility
    Private mFilterCollection As New Collection

    Private Sub LoadFilterList()
        'Open the file stream
        Dim fs As IO.FileStream = New IO.FileStream(My.Application.Info.DirectoryPath & "/file.flt", IO.FileMode.OpenOrCreate, IO.FileAccess.Read)
        Dim sr As New IO.StreamReader(fs)
        Dim N As Integer
        Dim mString As String
        Dim mFilter As SelectionFilterCollection
        Dim varValues As String()
        'Seek the beginning of the file
        sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
        'Create our class to hold the filter information
        'this is necessary at this point to aleviate
        'a warning that an uninitialized variable may
        'cause an error
        mFilter = New SelectionFilterCollection
        While sr.EndOfStream <> True
            mString = sr.ReadLine()
            'If we have a header i.e. filter name
            If mString.Substring(0, 3) = "***" Then
                'Create a new SelectionFilterCollection to hold it
                'recycling the previous mFilter
                'We need to do this each time a new filter is found
                'in the file stream
                mFilter = New SelectionFilterCollection
                'Add the filter name to the combo box
                Me.ComboBox1.Items.Add(mString.Substring(3))
                'Set the Filter collection name to the same name so we
                'can identify it later when it is selected in the
                'ComboBox
                mFilter.Name = mString.Substring(3)
            Else
                'We don't have a filter header, so we must have filter
                'information in tab delimited format
                'so split it into the 3 parts
                varValues = Split(mString, vbTab)
                'and add those parts to our filter items
                'See the SelectionFilterCollection Class for information on its structure
                mFilter.Add(varValues(0), varValues(1), varValues(2))
            End If
            'If we have anything in the collection already ...
            If mFilterCollection.Count > 0 Then
                'make sure it isn't duplicated ...
                If mFilterCollection.Item(mFilter.Name.ToString) Is Nothing Then
                    'then add it if needed
                    mFilterCollection.Add(mFilter, mFilter.Name)
                End If
            Else
                'otherwise just add it
                mFilterCollection.Add(mFilter, mFilter.Name)
            End If
        End While
        'release the filter
        mFilter = Nothing
        'close the file stream
        sr.Close()
    End Sub

End Class

Class SelectionFilterCollection
    'This class is designed to hold multiple
    'block filters as an array of items
    'FilterItem is a class that holds a block name
    'attribute tag and a segregation value

    'Define public members
    Public Name As String
    Public Item As FilterItem()

    'New method
    Public Sub New()
        Name = ""
    End Sub

    'Add method
    Public Function Add(ByVal BlockName As String, ByVal Attribute As String, ByVal Segregate As String) As FilterItem
        If Item Is Nothing = True Then
            ReDim Item(0)
        Else
            ReDim Preserve Item(UBound(Item) + 1)
        End If
        Dim NItem As New FilterItem
        NItem.BlockName = BlockName
        NItem.Attribute = Attribute
        NItem.Segregate = Segregate
        Item(UBound(Item)) = NItem
        Return NItem
    End Function

    'Count method
    Public Function Count() As Integer
        If Item Is Nothing = True Then
            Return 0
        Else
            Return (UBound(Item) + 1)
        End If
    End Function
End Class

Class FilterItem
    'This class is designed to hold a block name
    'an attribute associated with that block and
    'whether or not the blocks should be identified
    'seperately based on the attribute value

    'Define public members
    Public BlockName As String
    Public Attribute As String
    Public Segregate As String

    'New method
    Public Sub New()
        BlockName = ""
        Attribute = ""
        Segregate = ""
    End Sub
End Class

This part seems to work correctly, as there are no errors generated (I removed all error checking to ensure it would break when running though the paces ...

However, when I change the combobox value (I added all of the filters in the above code) it crashes when I select the last item in the collection ...

Code: [Select]
    Private Sub ComboBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
        Dim mFilter As SelectionFilterCollection
        Dim mListItem As ListViewItem
        'If we don't have an unnamed filter
        'and if we are not saving additional
        'data to the collection
        If IsUnnamed() = False And mSavingData = False Then
            'Clear the listview showing the filter criteria
            If Me.ListView1.Items.Count > 0 Then
                Me.ListView1.Items.Clear()
            End If
            'Set the filter collection to the item referenced
            'in the collection, searching by "key name" (override 2)
            mFilter = mFilterCollection.Item(Me.ComboBox1.Text)
            'If we have a filter
            If mFilter Is Nothing = False Then
                'loop through each one in the collection of items
                For Each fItem As FilterItem In mFilter.Item
                    'putting the data in the listview
                    mListItem = Me.ListView1.Items.Add(fItem.BlockName)
                    mListItem.SubItems.Add(fItem.Attribute)
                    mListItem.SubItems.Add(fItem.Segregate)
                    'release the list item
                    mListItem = Nothing
                Next
            End If
        End If
    End Sub

The program crashes and burns here saying that the object is not set .. I am not sure why ...

Code: [Select]
mFilter = mFilterCollection.Item(Me.ComboBox1.Text)

but only if I select the last item in the collection ... if there are 4 items, I can select the first three without a problem

Ideas?
Am I not putting the last item in the collection when I build it?
Is there an easier way?

Ok .. ignore that last question ... sure there is an easier way ... 'cause I ain't using it
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

fixo

  • Guest
Re: Variable not set to object - why?
« Reply #1 on: November 16, 2009, 02:22:26 PM »
At the first glance the problem is here:
Code: [Select]
Dim mListItem As ListViewItemmust be
Code: [Select]
Dim mListItem As ListViewItem = New ListViewItem
Not tested of course

~'J'~

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Variable not set to object - why?
« Reply #2 on: November 16, 2009, 02:35:04 PM »
that shouldn't the issue ... otherwise it wouldn't work on the first few items

Incidently, I added alot of error checking to the file reading and the problem seems to be that the last item isn't added for some reason.

It seems to fail on this bit ...

Code: [Select]
If mFilterCollection.Item(mFilter.Name.ToString) Is Nothing Then
        mFilterCollection.Add(mFilter, mFilter.Name)
End If

Evidently, I cannot search the collection for a key ... is this correct?
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

n.yuan

  • Bull Frog
  • Posts: 348
Re: Variable not set to object - why?
« Reply #3 on: November 16, 2009, 02:55:54 PM »
That is NOT a problem: mListItem should not be declares as "New", because in the following code, this variable is assigned to a ListViewItem that is created by ListView.Items.Add() method.

To the OP:

The code should fail on the line

If mFilterCollection.Item(mFilter.Name.ToString) Is Nothing Then
        mFilterCollection.Add(mFilter, mFilter.Name)
End If

You did not indicate what type of collection the mFilterCollection is (a Dictionary, most likely?). Anyway, as standard KeyedCollection's behaviour when a non-existing key is passed into its Item() method, it raises "KeyNotFoundException", not returns Nothing, as your code assumes, unless your collection overides the Item() method and specifically handled KeyNotFoundException and returns Nothing.

So, your code should be (assume it is a Dictionary)

If mFilterCollection.ContainsKey(TheKey) Then
    ''The collection has already an item with that key in it
Else
    ''The collection does not have a record with the given key
End


At the first glance the problem is here:
Code: [Select]
Dim mListItem As ListViewItemmust be
Code: [Select]
Dim mListItem As ListViewItem = New ListViewItem
Not tested of course

~'J'~

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Variable not set to object - why?
« Reply #4 on: November 16, 2009, 03:11:07 PM »
n.yuan , thanks .. that solved the problem

The collection is a generic collection type in VB.Net and not an AutoCAD collection. I use it to hold filter settings so the user can select them from a combobox ...
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

fixo

  • Guest
Re: Variable not set to object - why?
« Reply #5 on: November 16, 2009, 03:50:32 PM »
That is NOT a problem: mListItem should not be declares as "New", because in the following code, this variable is assigned to a ListViewItem that is created by ListView.Items.Add() method.

To the OP:

The code should fail on the line

If mFilterCollection.Item(mFilter.Name.ToString) Is Nothing Then
        mFilterCollection.Add(mFilter, mFilter.Name)
End If

You did not indicate what type of collection the mFilterCollection is (a Dictionary, most likely?). Anyway, as standard KeyedCollection's behaviour when a non-existing key is passed into its Item() method, it raises "KeyNotFoundException", not returns Nothing, as your code assumes, unless your collection overides the Item() method and specifically handled KeyNotFoundException and returns Nothing.

So, your code should be (assume it is a Dictionary)

If mFilterCollection.ContainsKey(TheKey) Then
    ''The collection has already an item with that key in it
Else
    ''The collection does not have a record with the given key
End


At the first glance the problem is here:
Code: [Select]
Dim mListItem As ListViewItemmust be
Code: [Select]
Dim mListItem As ListViewItem = New ListViewItem
Not tested of course

~'J'~

Sorry, my bad
Thanks for the explanations

~'J'~

Ken Alexander

  • Newt
  • Posts: 61
Re: Variable not set to object - why?
« Reply #6 on: November 16, 2009, 09:18:51 PM »
I know you received an answer, but I would also suggest putting all of your logic into your specialized collection classes.  

Right now you have business logic in your UI; this makes it difficult to re-use your collection. Here are three classes that pretty much handle what the UI was taking care of.  You’ll notice that the add method of the FilterCollection now can determine if there is already one in the collection.  I also overloaded the Item property to allow for a string to be passed in returning a matching object from the collection, if there is one.  Other than that, your original two classes are still pretty much the same.

Maybe turn OptionStrict On as well.

Code: [Select]
Public Class FilterCollection
    Inherits List(Of SelectionFilterCollection)

    Private Shared _NameMatch As String = ""

    Public Shadows Sub Add(ByVal item As SelectionFilterCollection)
        If Not Me.Contains(item) Then
            MyBase.Add(item)
        Else
            'do what ever
        End If
    End Sub

    Public Sub MakeCollection(ByVal FullFileName As String)
        Using fs As IO.FileStream = New IO.FileStream(FullFileName, IO.FileMode.OpenOrCreate, IO.FileAccess.Read)
            Using sr As New IO.StreamReader(fs)
                Dim mString As String
                Dim mFilter As SelectionFilterCollection
                Dim varValues As String()
                'Seek the beginning of the file
                sr.BaseStream.Seek(0, IO.SeekOrigin.Begin)
                'Create our class to hold the filter information
                'this is necessary at this point to aleviate
                'a warning that an uninitialized variable may
                'cause an error
                mFilter = New SelectionFilterCollection
                While sr.EndOfStream <> True
                    mString = sr.ReadLine()
                    'If we have a header i.e. filter name
                    If mString.Substring(0, 3) = "***" Then
                        'Create a new SelectionFilterCollection to hold it
                        'recycling the previous mFilter
                        'We need to do this each time a new filter is found
                        'in the file stream
                        mFilter = New SelectionFilterCollection
                        'Set the Filter collection name to the same name so we
                        'can identify it later when it is selected in the
                        'ComboBox
                        mFilter.Name = mString.Substring(3)
                    Else
                        'We don't have a filter header, so we must have filter
                        'information in tab delimited format
                        'so split it into the 3 parts
                        varValues = Split(mString, vbTab)
                        'and add those parts to our filter items
                        'See the SelectionFilterCollection Class for information on its structure
                        mFilter.Add(varValues(0), varValues(1), varValues(2))
                    End If
                    'If we have anything in the collection already ...
                    Me.Add(mFilter)
                End While
                'release the filter
                mFilter = Nothing
                'close the file stream
                sr.Close()
            End Using
        End Using
    End Sub

    Default Public Overloads ReadOnly Property Item(ByVal Name As String) As SelectionFilterCollection
        Get
            _NameMatch = name
            Return Me.Find(AddressOf MatchName)
        End Get
    End Property

    Private Shared Function MatchName(ByVal item As SelectionFilterCollection) As Boolean
        Return item.Name = _NameMatch
    End Function
End Class


Public Class SelectionFilterCollection
    Inherits List(Of FilterItem)
    Implements IEquatable(Of SelectionFilterCollection)

    Private _Name As String = ""

    Public Property Name() As String
        Get
            Return _Name
        End Get
        Set(ByVal value As String)
            _Name = value
        End Set
    End Property

    Public Function DoSomething() As Boolean
        Return False
    End Function

    'Add method
    Public Overloads Function Add(ByVal BlockName As String, ByVal Attribute As String, ByVal Segregate As String) As FilterItem
        Dim NItem As New FilterItem
        NItem.BlockName = BlockName
        NItem.Attribute = Attribute
        NItem.Segregate = Segregate
        Me.Add(NItem)
        Return NItem
    End Function

    Public Overloads Function Equals(ByVal other As SelectionFilterCollection) As Boolean Implements System.IEquatable(Of SelectionFilterCollection).Equals
        Return Me.Name.Equals(other.Name)
    End Function
End Class

Public Class FilterItem
    Private _BlockName As String = ""
    Private _Attribute As String = ""
    Private _Segregate As String = ""

    Public Property Attribute() As String
        Get
            Return _Attribute
        End Get
        Set(ByVal value As String)
            _Attribute = value
        End Set
    End Property

    Public Property BlockName() As String
        Get
            Return _BlockName
        End Get
        Set(ByVal value As String)
            _BlockName = value
        End Set
    End Property

    Public Property Segregate() As String
        Get
            Return _Segregate
        End Get
        Set(ByVal value As String)
            _Segregate = value
        End Set
    End Property
End Class
« Last Edit: November 16, 2009, 09:22:18 PM by Ken Alexander »
Ken Alexander