ByVal does work not correctly in VB.NET - vb.net

I have a code in VB.NET like this:
' This code will sort array data
Public Sub SelectionSort(ByVal array as ArrayList)
For i as Integer = 0 To array.Count -1
Dim index = GetIndexMinData(array, i)
Dim temp = array(i)
array(i) = array(index)
array(index) = temp
Next
End Sub
Public Function GetIndexMinData(ByVal array As ArrayList, ByVal start As Integer) As Integer
Dim index As Integer
Dim check As Integer = maxVal
For i As Integer = start To Array.Count - 1
If array(i) <= check Then
index = i
check = array(i)
End If
Next
Return index
End Function
' This code will sort array data
Public Sub SelectionSortNewList(ByVal array As ArrayList)
Dim temp As New ArrayList
' Process selection and sort new list
For i As Integer = 0 To array.Count - 1
Dim index = GetIndexMinData(array, 0)
temp.Add(array(index))
array.RemoveAt(index)
Next
End Sub
Private Sub btnProcess_Click(sender As System.Object, e As System.EventArgs) Handles btnProcess.Click
Dim data as new ArrayList
data.Add(3)
data.Add(5)
data.Add(1)
SelectionSort(data)
SelectionSortNewList(data)
End Sub
When I run this code, in the btnProcess event click, variable "data" is array = {3,5,1}. By SelectionSort(data) procedure, variable data is changed. Item in variable data have sorted by that procedure, so when SelectionSortNewList(data) is run, array "data" have sorted became {1,3,5}. Why does it happen?
Although I have used "Byval parameter" in SelectionSort and SelectionSortNewList, I don't want variable data to be changed when it pass to SelectionSort.

Even if you use a ByVal on an object, the properties of the object can be modified.
The instance of the object cannot be modified but not its properties.
Example:
Public Class Cars
Private _Make As String
Public Property Make() As String
Get
Return _Make
End Get
Set(ByVal value As String)
_Make = value
End Set
End Property
End Class
If I pass the class as ByVal;
Private sub Test(ByVal MyCar as Car)
MyCar.Make = "BMW"
End Sub
The value of the property will change as you're pointing to the same object and modifying its property.

Related

Problem populating DataGridView with Structured Array

When I run my code, populating the array with data from a csv logfile, the DataGridView populates with empty rows.
I have tried just using a 2 Dimensional Array, I get the same results. I suspect I need to "map" the data in some fashion... maybe?
Here is what I am currently attempting:
This first section is in a Module..., the sub in the form code
Public Structure DataBlock
Public Data As String()
Public Property xData As String()
Get
Return Data
End Get
Set(ByVal value As String())
Data = value
End Set
End Property
End Structure
Public DataBlocks(1) As DataBlock
' end of module code
' start of form code
Public Sub test(path)
Dim i As Integer
LogData = IO.File.ReadAllLines(path)
ReDim DataBlocks(UBound(LogData))
For i = 0 To UBound(LogData)
DataBlocks(i) = New DataBlock With {.xData = Split(LogData(i), ",")}
Next
DataGridView1.DataSource = DataBlocks
End Sub
I was expecting the table to be populated I see other examples which work, but these do not use a structured array with an array in the structure. I could just break the array down in to 8 parts (that's my column count for the file), but I'm not willing to secede just yet.
Well, it's a bit kludgy but it works. I changed the structure to a class. It seems the DataGridView can not handle an array as a column type so I changed the array to a string for display.
Public Class DataBlock
Private Data As String()
Public ReadOnly Property xDataOut As String
Get
Return String.Join(", ", Data)
End Get
End Property
Public WriteOnly Property xDataIn As String()
Set(value As String())
Data = value
End Set
End Property
Public Sub New(sArray As String())
xDataIn = sArray
End Sub
End Class
Public DataBlocks As New List(Of DataBlock)
Public Sub test(path As String)
Dim Lines = IO.File.ReadAllLines(path)
For Each line In Lines
DataBlocks.Add(New DataBlock(line.Split(","c)))
Next
DataGridView1.DataSource = DataBlocks
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
test("LogData.txt")
End Sub

Is there a way to pass a given property identifier into a Sub as a parameter in VB?

I'm trying to create a generic BubbleSort subroutine to be used throughout my program. As such, I would like to be able to Sort a List by any given Property (e.g. Index, Health, Name etc.) . My issue is that I don't seem to be able to pass a property identifier into the sub. How do I go about implementing this?
I tried to pass the Property in as an object to no avail.
My attempt to call the sub:
AscendingBubbleSort(Party, Character.Health)
The Sub itself:
Sub AscendingBubbleSort(ByRef List As List(Of Object), ByRef ListProperty As Object)
Dim Swap As Boolean = False
Dim Temp As New Object
Do
Swap = False
For i = 0 To ((List).Count - 2)
If List(i).ListProperty < List(i + 1).ListProperty Then
Temp = List(i)
List(i) = List(i + 1)
List(i + 1) = Temp
Swap = True
End If
Next
Loop Until Swap = False
End Sub
I expected the "Party" List to be sorted by Ascending Health, but my program wouldn't compile, citing the following build error:
reference to a non-shared member requires an object reference
with "Character.Health" highlighted as the offending code.
Here's an example using Generics and a Lamba.
Note that you need to change your comparison from < to > if you want an ascending sort as indicated in the title of your subroutine!
Also note the use of ByVal instead of ByRef in the parameters. ByRef is only necessary when you want to point the variable passed in to a completely new instance that is created within the subroutine.
With this setup, you can specify what to sort on like this:
AscendingBubbleSort(objects, Function(x) x.SomeProperty)
' < or >
AscendingBubbleSort(objects, Function(x) x.SomeOtherProperty)
The code:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim objects As New List(Of SomeClass)
objects.Add(New SomeClass() With {.SomeProperty = 5, .SomeOtherProperty = "Bob"})
objects.Add(New SomeClass() With {.SomeProperty = 1, .SomeOtherProperty = "Jane"})
objects.Add(New SomeClass() With {.SomeProperty = 7, .SomeOtherProperty = "Cathy"})
AscendingBubbleSort(objects, Function(x) x.SomeOtherProperty)
For Each sc As SomeClass In objects
Debug.Print(sc.ToString)
Next
End Sub
Sub AscendingBubbleSort(Of T)(ByVal List As List(Of T), ByVal ListPropery As Func(Of T, Object))
Dim Swap As Boolean = False
Dim Temp As New Object
Do
Swap = False
For i = 0 To ((List).Count - 2)
If ListPropery(List(i)) > ListPropery(List(i + 1)) Then
Temp = List(i)
List(i) = List(i + 1)
List(i + 1) = Temp
Swap = True
End If
Next
Loop Until Swap = False
End Sub
End Class
Public Class SomeClass
Public Property SomeProperty As Integer
Public Property SomeOtherProperty As String
Public Overrides Function ToString() As String
Return SomeProperty & ": " & SomeOtherProperty
End Function
End Class

Listbox Sorting Issue

I am having trouble sorting a listbox the way I am expecting it to work even using the sorted = true property. Assuming i have files named as such, when i sort by "Name" in a Windows Folder view (outside of vb) it sorts like so:
1180741
1179715
1162371
1141511
1131750
1117362
1104199
1082698
1062921
1043875
991514
970621
963154
952954
948067
917669
904315
899902
892398
882024
This is how i need it to be sorted in my list. However, with the sorted = true property, vb.net decides to sort like this:
1043875
1062921
1082698
1104199
1117362
1131750
1141511
1162371
1179715
1180741
882024
892398
899902
904315
917669
948067
952954
963154
970621
991514
I cannot understand why windows sorts the list correctly but VB does not. Any help would be most appreciated.
*This example assumes that each object in the listbox is a string representation of an integer, if in the case that it is not, the item will be skipped, you can modify this to handle such a case in another way if you want....
Example:
Option Strict On
Option Explicit On
Option Infer Off
Public Class Form1
Dim r As New Random(Now.Millisecond)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
'We simulated a populated listbox
For I As Integer = 0 To 1000
Dim n As Integer = r.Next(0, Integer.MaxValue)
ListBox1.Items.Add(n.ToString)
Next
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
SortListBoxNumbers(ListBox1)
End Sub
Sub SortListBoxNumbers(listbox As ListBox)
Dim numbers As New List(Of Integer)
For Each item As Object In listbox.Items
Dim n As Integer = 0
If item.GetType = GetType(String) Then
If Integer.TryParse(DirectCast(item, String), n) Then
numbers.Add(n)
End If
End If
Next
listbox.Items.Clear()
numbers = SortNumbers(numbers)
For Each n As Integer In numbers
listbox.Items.Add(n.ToString)
Next
End Sub
Function SortNumbers(numbers As List(Of Integer)) As List(Of Integer)
Dim result As New List(Of Integer)
Dim count As Integer = numbers.Count
Do
Dim highN As Integer = Integer.MinValue
For Each n As Integer In numbers
If n > highN Then highN = n
Next
numbers.Remove(highN)
result.Insert(result.Count, highN)
Loop Until result.Count = count
result.Reverse()
Return result
End Function
End Class

sort results (find method) not working

I am using ArcGIS. I am trying to sort the data manually after its found. I created a property class and loop through a Tlist to scrub unwanted data. However right before it binds to the data grid, I receive a cast error. I assume something is coming back null. Am I missing something??
Public Class temp
Public Sub New()
End Sub
Public Property DisplayFieldName As String
Public Property Feature As ESRI.ArcGIS.Client.Graphic
Public Property FoundFieldName As String
Public Property LayerId As Integer
Public Property LayerName As String
Public Property Value As Object
End Class
Public Class templst
Public Sub New()
Dim findresult = New List(Of temp)
End Sub
Private _findresult = findresult
Public Property findresult() As List(Of temp)
Get
Return _findresult
End Get
Set(ByVal value As List(Of temp))
_findresult = value
End Set
End Property
End Class
Private Sub FindTask_Complete(ByVal sender As Object, ByVal args As FindEventArgs)
Dim newargs As New templst() 'puts Tlist (temp) into property
Dim templistNUMONLY As New List(Of temp) 'Tlist of temp
For Each r In args.FindResults 'class in compiled dll.
If Regex.Match(r.Value.ToString, "[0-9]").Success Then
templistNUMONLY.Add(New temp() With {.LayerId = r.LayerId,
.LayerName = r.LayerName,
.Value = r.Value,
.FoundFieldName = r.FoundFieldName,
.DisplayFieldName = r.DisplayFieldName,
.Feature = r.Feature})
End If
Next
newargs.findresult = templistNUMONLY
Dim sortableView As New PagedCollectionView(newargs.findresult)
FindDetailsDataGrid.ItemsSource = sortableView 'populate lists here
End Sub
BIND TO GRID HERE: (Error here)
Private Sub FindDetails_SelectionChanged(ByVal sender As Object, ByVal e As SelectionChangedEventArgs)
' Highlight the graphic feature associated with the selected row
Dim dataGrid As DataGrid = TryCast(sender, DataGrid)
Dim selectedIndex As Integer = dataGrid.SelectedIndex
If selectedIndex > -1 Then
'''''''''''''''''CAST ERROR HERE:
Dim findResult As FindResult = CType(FindDetailsDataGrid.SelectedItem, FindResult)
You populate FindDetailsDataGrid with objects of type temp, but you try to cast it to type FindResult instead. You should do:
Dim selectedTemp As temp = CType(FindDetailsDataGrid.SelectedItem, temp)
'*Create find result from selected temp object here*

get an array into a class.property

I have a class with the following properties:
Dim pBonds() as string
Private Property Get Bonds() As String
Bonds = pBonds
End Property
Private Property Get Bond(index As Long) As String
Bond = pBonds(index)
End Property
Private Property Let Bond(index As Long, strValue As String)
If index > UBound(pBonds) Then ReDim Preserve pBonds(index)
pBond(index) = strValue
End Property
when I try:
Set o = New CBondBasket
For k = LBound(arr) To UBound(arr)
o.Bond(k) = arr(k)
Next k
I get error Method or data member not found
Any idea where that comes from?
made the changes
marked them as public now and added initialization and byval (got me another error w/o it)
Private Sub Class_Initialize()
ReDim pBonds(0)
End Sub
Public Property Get Bonds() As String()
Bonds = pBonds
End Property
Public Property Get Bond(index As Long) As String
Bond = pBonds(index)
End Property
Public Property Let Bond(ByVal index As Long, ByVal strValue As String)
If index > UBound(pBonds) Then ReDim Preserve pBonds(index)
pBonds(index) = strValue
End Property
error is: Definitions of property procedures for the same property are inconsistent or property procedure has an optional parameter, a ParamArray or an invalid set final parameter can anyone help me with that? thanks
You also need to initialise the pBonds array or you will get an error when calling UBound the first time:
Main module
Option Explicit
Sub testClass()
Dim o As CBondBasket
Dim k As Long
Dim arr As Variant
arr = Array(1, 2, 3, 4, 5)
Set o = New CBondBasket
For k = LBound(arr) To UBound(arr)
o.Bond(k) = arr(k)
Next k
For k = LBound(o.Bonds) To UBound(o.Bonds)
Debug.Print o.Bond(k)
Next k
End Sub
Class CBondBasket
Private pBonds() As String
Private Sub Class_Initialize()
ReDim pBonds(0)
End Sub
Public Property Get Bonds() As String()
Bonds = pBonds
End Property
Public Property Get Bond(index As Long) As String
Bond = pBonds(index)
End Property
Public Property Let Bond(index As Long, strValue As String)
If index > UBound(pBonds) Then ReDim Preserve pBonds(index)
pBonds(index) = strValue
End Property
Your class methods are marked Private if you want to expose them to automation clients make them Public.
(You also need parens to return an array: Public Property Get Bonds() As String())
Option Compare Database
Option Explicit
Public Function test1() As Integer
Dim sdate(2) As Date
Dim edate(2) As Date
Dim serdat As Class_erviceDate
sdate(1) = #1/2/2015#
edate(1) = #10/21/2015#
sdate(2) = #2/5/2015#
edate(2) = #12/25/2015#
Set serdat = New Class_ServiceDate
serdat.serviceStart = sdate
serdat.serviceEnd = edate
Debug.Print serdat.serviceStart(1), serdat.serviceEnd(1)
Debug.Print serdat.serviceStart(2), serdat.serviceEnd(2)
End Function
Option Compare Database
Option Explicit
Private f_datServiceStart As Variant
Private f_datServiceEnd As Variant
Public Property Get serviceStart() As Variant
serviceStart = f_datServiceStart
End Property
Public Property Let serviceStart(Value As Variant)
f_datServiceStart = Value
End Property
Public Property Get serviceEnd() As Variant
serviceEnd = f_datServiceEnd
End Property
Public Property Let serviceEnd(Value As Variant)
f_datServiceEnd = Value
End Property