Index out of bound of the array in VB - asp.net

So I'm trying to put a 2D array into 2 arrays but I keep getting index out of the bounds of the array. The reason you might ask of why I'm doing this is so that I can store it in a viewstate object so I don't have to continuously retrieve my data.
The code I've been trying to use is this:
Dim testArray As String() = {}
testArray(0) = dataArray(0, 1)
and if there is a way to store a 2D array in a viewstate, let me know. Thanks!
Oh, I'm sorry, Heres the dataArray code
Private Function getDataArray() As Array
Dim x As Integer
Dim DT As DataTable
Dim TA As New DSOldOrdersTableAdapters.TA
DT = getOldOrders()
ReDim dataArray(3, DT.Rows.Count - 1)
For x = 0 To DT.Rows.Count - 1
dataArray(0, x) = DT.Rows(x).Item("SO")
dataArray(1, x) = DT.Rows(x).Item("Customer")
dataArray(2, x) = DT.Rows(x).Item("ShipBy")
Next
Return dataArray
End Function

Dim testArray As String() = {}
testArray(0) = dataArray(0, 1)
You're declaring testArray and assigning an empty array to it. Because the array is zero-length, there is no index 0, so trying to assign to testArray(0) results in an index out of bounds exception.
You need to ReDim the testArray variable, or change your assignment:
Dim testArray As String() = {}
ReDim testArray(0)
testArray(0) = dataArray(0, 1)
'or
Dim testArray As String() = {dataArray(0,1)}

Declaring
Dim testArray As String() = {}
created a string array with a dimension set to zero
So testArray is useless without a dimensioning of at least one element.
Writing
testArray(0) = dataArray(0, 1)
cause the Index Out Of bound exception
Probably you need an array of the same length of your datatable rows.
But, why all the effort to use an array in this context?.
A List(Of String) is a better solution
Dim testValues = new List(Of String)()
testValues.Add(dataArray(0,1))
In this way you don't need to know how big the testArray should be and you could use the List as an array in every place where it is required to have the array
Dim soValue = testValues(0)
or
testValues.ToArray()

The error you're having would be because, the element you're trying to refer to is not present in the Array. Index of an array starts at 0, so always try to make sure, you're refering the last element to be (maxElements - 1). Otherwise it would cause an error and you'll see this error.

Related

Access VB property based on name as string - Fastest Option

I'm developing an ASP.NET MVC web app in VB and I am required to output a set of data to a table format, and to allow the user to configure the order and presence of columns from an available set. The data set is stored as a list of the object type representing the row model.
Currently, I implement this using CallByName. Iterating over an ordered list of property names and outputting the value from the instance of the row model. However, based on testing this seems to be a major bottleneck in the process.
I've seen a recommendation to store delegates to get the property, against the string representation of the property's name. So, I can presumably do something like this:
Public Delegate Function GetColumn(ByRef RowObj As RowModel) As String
Dim GetPropOne As GetColumn = Function(ByRef RowObj As RowModel) RowObj.Prop1.ToString()
Dim accessors As New Hashtable()
accessors.Add("Prop1", GetPropOne)
Then, loop through and do something like this:
Dim acc As GetColumn = accessors(ColumnName)
Dim val As String = acc.Invoke(currentRow)
It looks faster, but it also looks like more maintenance. If this is indeed faster, is there a way I can dynamically build something like this? I'm thinking:
Public Delegate Function GetObjectProperty(Instance As Object) As Object
For Each prop In GetType(RowModel).GetProperties()
Dim acc As GetObjectProperty = AddressOf prop.GetValue
columns.Add(prop.Name, acc)
Next
Dim getColVal As GetObjectProperty = columns(ColumnName)
Dim val As String = getColVal.Invoke(currentRow).ToString()
Open to suggestions for different approaches.
I do a similar thing to turn a SOAP response into a Data Table
Public Function ObjectToDataSource(objName) As DataSet
Dim CollName = ""
Dim ds As New DataSet()
For Each m As System.Reflection.PropertyInfo In objName.GetType().GetProperties()
If m.CanRead Then
If InStr(m.PropertyType.ToString, "[]") <> 0 Then
CollName = m.Name
Exit For
End If
End If
Next
Dim CollObj
CollObj = CallByName(objName, CollName, CallType.Get)
If CollObj.length = 0 Then
Call EndTask("No Supply Chains to display", "Royal Mail failed to return Supply Chain information for these credentials", 3)
Else
Dim dt_NewTable As New DataTable(CollName)
ds.Tables.Add(dt_NewTable)
Dim ColumnCount = 0
For Each p As System.Reflection.PropertyInfo In CollObj(0).GetType().GetProperties()
If p.CanRead Then
If p.Name <> "ExtensionData" Then
dt_NewTable.Columns.Add(p.Name, p.PropertyType)
ColumnCount = ColumnCount + 1
End If
End If
Next
Dim rowcount = CollObj.Length - 1
For r = 0 To rowcount
Dim rowdata(ColumnCount - 1) As Object
For c = 0 To ColumnCount - 1
rowdata(c) = CallByName(CollObj(r), dt_NewTable.Columns.Item(c).ToString, CallType.Get)
Next
dt_NewTable.Rows.Add(rowdata)
rowdata = Nothing
Next
End If
Return ds
End Function
This is specific to my needs in terms of getting CollName and not requiring ExtensionData
If ColumnName is the same name as one of the RowModel's properties I don't see why you need the long workaround with delegates...
An extension method which gets only the property you want right now is both faster and consumes less memory.
Imports System.Runtime.CompilerServices
Public Module Extensions
<Extension()> _
Public Function GetProperty(ByVal Instance As Object, ByVal PropertyName As String, Optional ByVal Arguments As Object() = Nothing) As Object
Return Instance.GetType().GetProperty(PropertyName).GetValue(Instance, Arguments)
End Function
End Module
Example usage:
currentRow.GetProperty("Prop1")
'or:
currentRow.GetProperty(ColumnName)

Can't get value in dim with CInt vb.net

I'm fairly new to vb.net and can't find why this is not working, dim test is just empty after this line happened. Any possible problems?
Dim test As Integer = CInt(System.Configuration.ConfigurationManager.AppSettings("TermstextFieldTypeId"))
Try this code;
If your TermstextFieldTypeId setting IsNullOrEmpty then get default(0) value else getter setting value.
Dim val = System.Configuration.ConfigurationManager.AppSettings("TermstextFieldTypeId")
Dim test As Integer = CInt(IIf(String.IsNullOrEmpty(val), 0, val))

ASP array element is null and conversion of string to long

I've inherited an ASP project, and I'm a PHP coder with no ASP knowledge. Sorry if this post is lengthy, I just want to give as much informations as possible.
I'm struggling with this one block of code.
Dim resultArray As String()
For Each resultitem In resultArray
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
Error:
Exception!!: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
The solution seems simple. Check if resultitem is null then either break or skip to the next element.
So I tried this:
If IsNull(resultitem) Then
Break
End If
Error:
BC30451: Name 'IsNull' is not declared.
I tried several other alternatives I found online:
IsEmpty(resultitem) - IsEmpty not declared
String.IsNullOrEmpty(resultitem) - index out of bounds error, seems to have no effect
resultitem Is Nothing - index out of bounds
Not (Len(resultitem) > 0) - index out of bounds
Len(resultitem) = 0 - index of out bounds
The only thing that seems to come close is:
If Not resultitem Then
Break
End If
Error:
Exception!!: Conversion from string "some_string_here" to type 'Long' is not valid.
If I use Next instead of Break I get this error:
If Not resultitem Then
Next
End If
Error:
BC30081: 'If' must end with a matching 'End If'.
Help!
I'm going to include the full block of code in case it is helpful
Dim isResultArray As Boolean
isResultArray = methodInf.ReturnType.IsArray()
If isResultArray Then
Dim resultArray As String()
'*** Invoke the dll function
resultArray = methodInf.Invoke(REMem, args.ToArray)
Dim i As Integer = 0
For Each resultitem In resultArray
If Not resultitem Then
Response.Write("Found null value.")
Exit For
End If
Response.Write("i: " & i & "<br />")
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
' i = 6 will cause Get Constituent Name to work
'If i = 6 Then
' Exit For
'End If
Next
outputArray.Add(hash)
Else
'*** could be boolean, string, long etc.
Dim result As String
'*** Invoke the dll function
result = methodInf.Invoke(REMem, args.ToArray)
hash.Add(dllFunctionObj.ReturnTemplateField(0), result)
outputArray.Add(hash)
End If
You need to make sure you're not overflowing the index of the collection you're accessing. Something like this should work:
If i < dllFunctionObj.ReturnTemplateField.Length Then
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
End If
Basically, you need to wrap your call to "hash.Add" in this if block to protect against accessing a value that doesn't exist.
Granted, I don't understand the purpose of the code, so you might need to handle the "else" case. But this should stop the error.
Looks to me like the array may be defined incorrectly.
Change this:
Dim resultArray As String()
For Each resultitem In resultArray
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
To this:
Dim resultArray() As String
For Each resultitem In resultArray()
' Do something with each element of the array
hash.Add(dllFunctionObj.ReturnTemplateField(i), resultitem)
i = i + 1
Next
Additionally, you may need to define the length of the array, e.g.:
Dim resultArray(0 to 9) As String
If the length of the array is unknown, you may define it without the minimum and maximum index, but will need to use ReDim to assign the minimum and maximum indexes later. One method would be to create the array without a length, count the items that you know will be added to the array, and then use ReDim with that count as the length of the array. For example:
Dim resultArray() As String
Dim iCount as integer 'Keep track of the count with this variable.
'Enter custom counting script here...Use a loop to count the items that will be used in the array.
ReDim resultArray(0 to iCount - 1) 'Subtract one from the iCount to match the 0-based index.
If you try to call upon a index of an array that has no set length (or use an index greater/less than the size of the array), you will most likely encounter either an "Index out of range" or "Substring out of range" error.

Why are the values in the array retained in the while loop? (VB.NET)

If I place a breakpoint at the line currentrow = MyParser.ReadFields()
, currentrow still contains the values of the previous line parsed from the file. After currentrow = MyParser.ReadFields()
executes, the current file line values are stored.
Since currentrow is declared inside the While loop, shouldn't the previous currentrow value be out of scope when re-entering the While loop? Why does currentrow still retain values from the last line in the file?
Do I need to change Dim currentrow As String()
to Dim currentRow() = New String() {}? Why?
If File.Exists(filename) Then
Using MyParser As New FileIO.TextFieldParser(filename)
MyParser.TextFieldType = FileIO.FieldType.Delimited
MyParser.SetDelimiters("~")
While Not MyParser.EndOfData
Try
Dim currentrow As String()
'at this point, currentrow still contains prev values
currentrow = MyParser.ReadFields()
Catch
End Try
End While
End Using
End If
Because you have only declared the loop variable, as against this which results in a correct value of Nothing on every iteration:
Dim currentrow As String() = Nothing
or even better
Dim currentrow As String() = MyParser.ReadFields()
"Dim" by itself, without the explicit initialization, will be optimized out as redundant.
Even if you assign Nothing, it will always be reset to Nothing on every iteration. If you only declare the variable it will always contain the "wrong" old value even if you would use Console.Write or MessageBox.Show afterwards.
So always assign a default value in a loop variable to avoid side-effects.
Sidenote C# avoids this error source with the compiler warning CS0165: Use of unassigned local variable 'variablename'.
So if you would try to use that unassigned variable before it gets assigned you would not even be able to compile with C#. I don't know why VB.NET allows it.
Remember that all variables in VB have a scope of the block they're declared in, but a lifetime of the whole routine(*) (effectively from where they are declared to the end of the routine), and they're always initialised to Nothing, whatever that means for the actual type.
Dim outer As Integer
For i = 1 To 2
Dim inner As Integer
Try
Dim inner2 As Integer
Do
Dim inner3 As Integer
While True
Dim inner4 As Integer
Console.WriteLine(outer & ", " & inner & ", " & inner2 & ", " & inner3 & ", " & inner4)
outer = i
inner = i
inner2 = i
inner3 = i
inner4 = i
Exit While
End While
Loop Until True
Catch
End Try
Next
The above outputs:
0, 0, 0, 0, 0
1, 1, 1, 1, 1
(*)Anonymous routines/closures affect this. See my separate question.

VB.net Null reference on database connection

I know I'm being an idiot here and I just can't work it out. But i'm trying to take some data back from a vb.net database. It's falling over with a Object reference not set to an instance of an object error. And before the code runs it's saying the variable is being used before it's set, but I can't see how. Code:
Private taNotifications As dsDataTableAdapters.NotificationsTableAdapter = New dsDataTableAdapters.NotificationsTableAdapter
Dim notification As dsData.NotificationsDataTable = taNotifications.GetDataByClientID(userrow.UserID)
If notification.Rows.Count > 0 Then
Dim notificationrow As dsData.NotificationsRow
Dim forwardURL As String = notificationrow.ForwardLocation
End If
It falls over on the Dim forwardURL As String = notificationrow.ForwardLocation
The problem is that you have never instantiated the notificationRow inside the if statement. You've declared it, but it doesn't belong to anything. You need to make an assignment or loop through your rows before doing anything with this object:
Dim notificationrow As dsData.NotificationsRow ' this is not instantiated
Dim forwardURL As String = notificationrow.ForwardLocation
What you really want in this case is:
For Each notificationRow As dsData.NotificationRow In notification
Dim forwardURL As String = notificationRow.ForwardLocation
' Do Something
Next
If you only HAVE one row and you know you only have 1 or 0 rows then you could use your if statement by doing:
If notification.Rows.Count > 0 Then
Dim notificationrow As dsData.NotificationsRow = _
CType(notification.Rows(0), dsData.NotificationsRow)
Dim forwardURL As String = notificationrow.ForwardLocation
End If
Edit: In the code above, I originally just had notification.Rows(0). This will produce a DataRow object, but it will not be strongly typed. You need to perform the CType that I added in order to use the custom property ForwardLocation.
You never set notificationrow to anything. Did you mean to set it like this?
Dim notificationrow As dsData.NotificationsRow = CType(notification.Rows(0), dsData.NotificationsRow)

Resources