Iterate through a dictionary of Subs/Functions and call them - vb.net

I'm trying to get the pointer to a function (like in C++) in VB.net and add it to a dictionary to be called later. I have no idea how to do this in VB but I know it's easily done in C++ using void*. I really want to avoid having 8000 global variables such as nextTime_RunSub1, nextTime_RunSub2, etc with a very big Select Case or If statement.
For example:
Public dictOfNewThinkFuncsToAdd As New Dictionary (Of ?, Single) 'Function/Sub, Time To Call
Private Sub Main()
Dim dictOfThinkFuncs As New Dictionary (Of ?, Single) 'Function/Sub, Time To Call
dictOfThinkFuncs.Add(AddressOf(Sub1), GetCurrentTime() + 5)
dictOfThinkFuncs.Add(AddressOf(Sub2), GetCurrentTime() + 6)
Dim removalQueue As New List(Of ?)
Do
Dim bRemoveFunc As Boolean = False
Dim bAddFunc As Boolean = False
For iter As Integer = 0 To dictOfThinkFuncs.Count - 1
If GetCurrentTime() >= dictOfThinkFuncs(iter).Value Then
CallFunction(dictOfThinkFuncs(iter).Key)
removalQueue.Add(dictOfThinkFuncs(iter).Key)
bRemoveFunc = True
End If
Next
If bRemoveFunc Then
For Each func In removalQueue
dictOfThinkFuncs.Remove(func)
Next
removalQueue.Clear()
End If
For Each func In dictOfNewThinkFuncsToAdd
dictOfThinkFuncs.Add(func.Key, func.Value)
bAddFunc = True
Next
If bAddFunc Then
dictOfNewThinkFuncsToAdd.Clear()
End If
Threading.Thread.Sleep(10)
Loop
End Sub
Private Sub Sub1()
DoStuff()
dictOfNewThinkFuncsToAdd.Add(AddressOf(Sub3), GetCurrentTime() + 15)
End Sub
Private Sub Sub2()
DoStuff()
dictOfNewThinkFuncsToAdd.Add(AddressOf(Sub2), GetCurrentTime() + 15)
End Sub
Private Sub Sub3()
DoStuff()
End Sub

This work (both formats). So you can either wrap your calls inside a uniform return or just do addressOf if they are all same type of function with no params.
It's not exactly your code (I know... I know). But gives you a quick example of a dictionary of Lambda functions. And it's vb.net.
Option Strict On
Module Module1
Sub Main()
Dim getters As New Dictionary(Of String, Func(Of Boolean))
getters.Add("First", New Func(Of Boolean)(Function()
Console.WriteLine("Test Run")
Return true
End Function))
getters.Add("Second", AddressOf TestMe)
For each el In getters.Values
el()
Next
End Sub
Public function TestMe() As boolean
Console.WriteLine("Test Run")
Return true
End function
End Module
Dictionary(of Action, Single) works too...
I guess you can do that without the return parameter, too (the vb.net equivalent of void function() is Sub() which is an object of type Action as seen below).
Module Module1
Sub Main()
Dim getters As New Dictionary(Of String, Action)
getters.Add("First", New Action(sub()
TestMe()
End sub))
getters.Add("Second", AddressOf TestMe2)
For each el In getters.Values
el()
Next
End Sub
Public Sub TestMe2()
Console.WriteLine("Test Run")
End Sub
Public function TestMe() As boolean
Console.WriteLine("Test Run")
Return true
End function
End Module

Related

How to input a procedure into another procedure

I have a code like below. This is main logic function and I'd like to insert different procedures in that procedure. So is it a way or solution to do that. I marked with **.
Public Shared Sub CheckListSubstrs(ByVal Substrs As IScrNamedObjectList, **mySub(Substr As IScrSubstructure)**)
Dim Substr As IScrSubstructure = Nothing
Dim nSubstr As Integer = Nothing
nSubstr = Substrs.count
If nSubstr > 0 Then
For i As Integer = 0 To nSubstr - 1
Substr = CType(Substrs.item(i), IScrSubstructure)
**mySub(Substr As IScrSubstructure)**
Next
End If
End Sub
I have different types of sub/func procedures and all of them uses Substr As IScr as Substructure as their input so I'd like to insert them dynamically and call them for different classes, modules.
EDIT
I have to clarify my problem more specific to clear conversations.
This is my class with all values.
Option Explicit On
Option Strict On
Imports simpackcomslvLib
Public Class Substr
Public Shared Sub CheckListSubstrs(ByVal Substrs As IScrNamedObjectList, ByVal dgv As DataGridView, SourceType As ****)
Dim nSubstr As Integer = Nothing
nSubstr = Substrs.count
If nSubstr > 0 Then
For i As Integer = 0 To nSubstr - 1
Dim Substr As IScrSubstructure = CType(Substrs.item(i), IScrSubstructure)
'Procedure comes here according to element type for example listing bodies
' CheckListBodies(Substr.getBodyList(False), DataGridView2)
'or if i list forces
'CheckListForces(Substr.getForceList(False), DataGridView3)
'Recursive usage function to get lower substructures information you can think there's a cascaded structure of substructures
CheckListSubstrs(Substrs:=Substr.getSubstrList(False), ProcedureForElementType As ****)
Next
End If
End Sub
Private Shared Sub CheckListBodies(ByVal Bodies As IScrNamedObjectList, ByVal dgv As DataGridView)
Dim nBody As Integer
nBody = Bodies.count
For i As Integer = 0 To nBody - 1
Dim Body As IScrBody = CType(Bodies.item(i), IScrBody)
dgv.Rows.Add(Body.fullName)
Next
End Sub
Private Shared Sub CheckListForces(ByVal Forces As IScrNamedObjectList, ByVal dgv As DataGridView)
Dim nForce As Integer
nForce = Forces.count
For i As Integer = 0 To nForce - 1
Dim Force As IScrForce = CType(Forces.item(i), IScrForce)
dgv.Rows.Add(Force.fullName)
Next
End Sub
Public Shared Sub RunTheCodeforBodies()
CheckListSubstrs(Mdl.getSubstrList(False), DataGridView2, getBodyList)
End Sub
Public Shared Sub RunTheCodeforForces()
CheckListSubstrs(Mdl.getSubstrList(False), DataGridView3, getForceList)
End Sub
End Class
As I showed two examples here, I'm listing different types approx. 30 types. I'm using com-interface and this Iscr types of classes from 3rd part software which I'm connecting.
So all of properties belongs to substructures and I only want to change function element type and output datagridview.
Since you already have existing methods that should elaborate a IScrSubstructure object and, as you say, all methods heve the same signature, you can use a method delegate with that same signature and use it as a parameter of the CheckListSubstrs sub.
A simulation, with some objects that can be used for testing:
Public Structure IScrSubstructure
Public value1 As String
Public value2 As Integer
End Structure
Public Class IScrNamedObjectList
Inherits List(Of IScrSubstructure)
End Class
Public Delegate Sub ScrSubstructureDelegate(ByVal Substr As IScrSubstructure)
Public Shared Sub CheckListSubstrs(ByVal Substrs As IScrNamedObjectList, MyDelegate As ScrSubstructureDelegate)
If Substrs?.Count > 0 Then
For Each item As IScrSubstructure In Substrs
MyDelegate(item)
Next
End If
End Sub
Now, your CheckListSubstrs method has a parameter:
MyDelegate As ScrSubstructureDelegate
you can pass any method that matches that signature:
ByVal Substr As IScrSubstructure
If you try to pass a method that doesn't match the delegate signature, the code will not compile.
So, lets build a couple of methods with these characteristics and call the CheckListSubstrs method using both methods as the MyDelegate parameter:
Public Sub MyIScrSub(ByVal Substr1 As IScrSubstructure)
'Do something with Substr1
Console.WriteLine("MyIScrSub Value1: {0}, MyIScrSub Value2: {1}", Substr1.value1, Substr1.value2)
End Sub
Public Sub MyOtherIScrSub(ByVal AnotherSubscr As IScrSubstructure)
'Do something with AnotherSubscr
Console.WriteLine("MyOtherIScrSub Value1: {0}, MyOtherIScrSub Value2: {1}", AnotherSubscr.value1, AnotherSubscr.value2)
End Sub
Now you can call CheckListSubstrs passing both MyIScrSub and MyOtherIScrSub methods as delegate:
Dim ScrList As IScrNamedObjectList = New IScrNamedObjectList()
ScrList.Add(New IScrSubstructure() With {.value1 = "Value1", .value2 = 1})
ScrList.Add(New IScrSubstructure() With {.value1 = "Value2", .value2 = 2})
ScrList.Add(New IScrSubstructure() With {.value1 = "Value3", .value2 = 3})
CheckListSubstrs(ScrList, AddressOf MyIScrSub)
CheckListSubstrs(ScrList, AddressOf MyOtherIScrSub)
As an note, in the CheckListSubstrs sub I wrote:
If Substrs?.Count > 0 Then
(...)
End If
so you can handle null values for the IScrNamedObjectList parameter:
(this syntax requires VB.Net 14 or newer)
CheckListSubstrs(nothing, AddressOf MyIScrSub)
but you could also write:
If Substrs IsNot Nothing Then
(...)
End If

Get elements with certain condition from List(Of)

I'm iterating through a List(Of MyClass) in order to find elements with certain conditions.
For example, in one case, I need to find all of these elements and do something with them:
For Each nCell As clsCell In colCell
If nCell.TempClickIndex = nCell.ClickIndex Then
If nCell.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE Then
I would like to know if there's any way to simplify this.
I'm dreaming of something like this:
For Each nCell As clsCell in colCell.GetSkypeCells()
The call "GetSkypeCells" would do just what I do above and would handle the selection internally.
Is there a way to do this?
Edit:
This is my colCell:
Public colCell As New clsCellListExtender.List(Of clsCell)
Imports System.Collections.ObjectModel
Public Class clsCellListExtender
Public Class List(Of T)
Inherits Collection(Of T)
Private _iID As Integer = 0
Private i As Integer = 0
Protected Overrides Sub InsertItem(index As Integer, item As T)
'your checks here
'i += 1
'If i > 20000 Then
' i = 0
'End If
Debug.Assert(g_bCheck = False)
If TypeOf (item) Is clsCell Then
_iID += 1
Dim nCell As clsCell = TryCast(item, clsCell)
nCell.TempID = _iID
End If
MyBase.InsertItem(index, item)
End Sub
End Class
End Class
You could use this:
For Each nCell as clsCell In colCell.Where(Function(x) x.TempClickIndex = x.ClickIndex AndAlso x.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE)
'Do stuff with nCell
Next
For your "dream" solution, you could add an extension method to whatever type colCell is that returns the result of the above LINQ.
Getting this to work with the nested class, and the generic type was a little tricky, but I finally got it.
Public Module Extensions
<System.Runtime.CompilerServices.Extension()> _
Public Function GetSkypeCells(Of T As clsCell)(colCell As clsCellListExtender.List(Of T)) As IEnumerable(Of T)
Return colCell.Where(Function(x) x.TempClickIndex = x.ClickIndex AndAlso x.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE)
End Function
End Module
Here is a small console application with a working extension method. I left the implementation blank to save space, but you should be able to fill it in from what is above. Just let me know if you have any issues.
Imports System.Collections.ObjectModel
Imports System.Runtime.CompilerServices
Module Module1
Sub Main()
Dim a As New clsCellListExtender.List(Of clsCell)
For Each cell As clsCell In a.GetSkypeCells()
'Do things with cell here
Next
End Sub
End Module
Public Class clsCellListExtender
Public Class List(Of T)
Inherits Collection(Of T)
Protected Overrides Sub InsertItem(index As Integer, item As T)
'...
End Sub
End Class
End Class
Public Class clsCell
'...
End Class
Module Extensions
<Extension>
Public Function GetSkypeCells(Of T As clsCell)(colCell As clsCellListExtender.List(Of T)) As IEnumerable(Of T)
Return colCell.Where(Function(x) x.TempClickIndex = x.ClickIndex AndAlso x.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE)
End Function
End Module
Try this:
For Each nCell As clsCell In colCell.FindAll(Function(c) c.TempClickIndex = c.ClickIndex And
c.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE)
Next
You can adapt this and create an extension-method, then you can call it with colCell.GetSkypeCells()
<Extension>
Public Function GetSkypeCells(c As List(Of clsCell)) As List(Of clsCell)
Return c.FindAll(Function(cc As clsCell) cc.TempClickIndex = cc.ClickIndex And
cc.StandardCellType = eStandardCellType.SCT_SKYPEMESSAGE)
End Function
You can use LINQ's extension method Where
Dim skypeCalls =
colCell.Where(Function(cell) cell.TempClickIndex = cell.ClickIndex).
.Where(Function(cell) cell.StandardCellType = eStandardCellType.SCT_SKYPEMESSAG)
For Each skypeCall in skypeCalls
' Do something
Next

Async and Await, why two return values

I'm trying to get my head around Async and Await. It's going well but one thing I would like clarification on is why there are two return statements in my method. I'm really looking for an explanation of what is actually happening behind the scenes.
I'll post the full code below as it only amounts to around 80 lines. I'm talking about the central method AllSubfolderFiles, which has both Return counter and Return dirsFraction. What's actually happening with these?
Basically, it is a WinForm application that iterates all the files of subfolders, updating a ProgressBar for each iterated subfolder.
Imports System.IO
Public Class frmAsyncProgress
Private Sub frmAsyncProgress_Load(sender As Object, e As EventArgs) Handles MyBase.Load
barFileProgress.Minimum = 0
barFileProgress.Maximum = 100
btnCancel.Enabled = False
End Sub
Private Async Sub btnStart_Click(sender As Object, e As EventArgs) Handles btnStart.Click
If String.IsNullOrWhiteSpace(txtPath.Text) Then
MessageBox.Show("Provide a location first.", "Location")
Exit Sub
End If
Dim sLocation As String = txtPath.Text.Trim()
If Not Directory.Exists(sLocation) Then
MessageBox.Show("Directory doesn't exist.", "Location")
Exit Sub
End If
Dim progressIndicator = New Progress(Of Integer)(AddressOf UpdateProgress)
btnStart.Enabled = False
btnCancel.Enabled = True
lblPercent.Text = "0%"
Dim allFiles As Integer = Await AllSubfolderFiles(sLocation, progressIndicator)
Debug.WriteLine(allFiles.ToString()) 'the number of subfolders iterated
btnStart.Enabled = True
btnCancel.Enabled = False
End Sub
Private Async Function AllSubfolderFiles(location As String, progress As IProgress(Of Integer)) As Task(Of Integer)
Dim dirsTotal As Integer = Directory.GetDirectories(location).Length
Dim dirsFraction As Integer = Await Task(Of Integer).Run(Function()
Dim counter As Integer = 0
For Each subDir As String In Directory.GetDirectories(location)
SubfolderFiles(subDir)
counter += 1
If progress IsNot Nothing Then
progress.Report(counter * 100 / dirsTotal)
End If
Next
Return counter
End Function)
Return dirsFraction
End Function
Private Sub UpdateProgress(value As Integer)
barFileProgress.Value = value
lblPercent.Text = (value / 100).ToString("#0.##%")
End Sub
Private Sub SubfolderFiles(location As String)
'source: http://stackoverflow.com/questions/16237291/visual-basic-2010-continue-on-error-unauthorizedaccessexception#answer-16237749
Dim paths = New Queue(Of String)()
Dim fileNames = New List(Of String)()
paths.Enqueue(location)
While paths.Count > 0
Dim sDir = paths.Dequeue()
Try
Dim files = Directory.GetFiles(sDir)
For Each file As String In Directory.GetFiles(sDir)
fileNames.Add(file)
Next
For Each subDir As String In Directory.GetDirectories(sDir)
paths.Enqueue(subDir)
Next
Catch ex As UnauthorizedAccessException
' log the exception or ignore it
Debug.WriteLine("Directory {0} could not be accessed!", sDir)
Catch ex As Exception
' log the exception or ...
Throw
End Try
End While
'could return fileNames collection
End Sub
End Class
My assessment is that counter is returned and then marshalled back onto the UI thread as dirsFraction, but I'm not convinced by my attempted explanation.
Inside your AllSubfolderFiles function you call Task.Run and pass in an anonymous function that returns with Return counter. AllSubfolderFiles awaits the result of that call and then returns with Return dirsFraction.
So, you have 2 returns in the same function because you have an anonymous function inside your original function. You can move that function out to its own named function which will make it clearer that there are 2 different functions here.

Populating a combo box with a list of functions - Need Advice

I'm looking for some advice on the best way to handle this.
I have a list of about 200 "Functions" which are listed in a combo box. When the user selects a 'function' from the list, I need to return the functionID (integer).
I know this can be done easily by binding a dataset to the key and value of the combobox, I'm just not sure about the best way to populate the dataset.
I feel that the way I'm doing it currently is very convoluted:
I currently have a txt file as an embedded resource which I write to a temporary directory, then I use the following code to read in that text file and populate that box by setting the combobox's datasource and Display Member. It does this by way of a custom class which is implementing System.Collections.IList.
I have pasted the code below. The reason I want to simplify it is that I dislike writing the text file to the disk, because sometimes it fails.
I'm looking for a way to populate my combobox and return my ID, without writing anything to the user's temp folder.
I am open to changing the format of the embedded resource, and or the code.
The fnlist.txt is formatted currently as follows.
index, Function Name, ID
The index is only included for sorting (to keep NONE at the bottom, and unknown function at the top), and I suppose is not strictly required.
#Region "Function lookup"
Dim path As String = System.IO.Path.GetTempPath
Dim _objFnXtef As New clsFunctionXref(path & "fnList.txt")
Private Sub populate_list()
functionlist.DataSource = _objFnXtef
functionlist.DisplayMember = "StrFunction"
End Sub 'Populates the function list
Function get_index(ByVal fnid As Integer)
Dim iLookupNumber As Integer = fnid
Dim tmpFnInfo As New clsFunctionInfo
Dim iReturnIdx As Integer = -1
If iLookupNumber <> 0 Then
tmpFnInfo.IFunctionNumber = iLookupNumber
iReturnIdx = _objFnXtef.IndexOf(tmpFnInfo)
If iReturnIdx <> -1 Then
Return iReturnIdx - 1
Else
Return get_index(9999)
End If
End If
Return 0
End Function 'Returns index of specified function number
#End Region 'All function list functions
Here is the code when a user changes the drop down:
Private Sub functionlist_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles functionlist.SelectedIndexChanged
Dim iReturnFuctionID As Integer = 0
Dim tmpFnInfo As New clsFunctionInfo
tmpFnInfo = _objFnXtef(functionlist.SelectedIndex)
iReturnFuctionID = tmpFnInfo.IFunctionNumber
Func = (iReturnFuctionID)
End Sub
And here is the supporting class:
Imports Microsoft.VisualBasic.FileIO
Public Class clsFunctionInfo
Private _idxFunction As Integer
Public Property IdxFunction() As Integer
Get
Return _idxFunction
End Get
Set(ByVal value As Integer)
_idxFunction = value
End Set
End Property
Private _strFunction As String
Public Property StrFunction() As String
Get
Return _strFunction
End Get
Set(ByVal value As String)
_strFunction = value
End Set
End Property
Private _iFunctionNumber As Integer
Public Property IFunctionNumber() As Integer
Get
Return _iFunctionNumber
End Get
Set(ByVal value As Integer)
_iFunctionNumber = value
End Set
End Property
End Class
Public Class clsFunctionXref
Implements System.Collections.IList
Private _colFunctionInfo As New Collection
Private _filePath As String
Public Property FilePath() As String
Get
Return _filePath
End Get
Set(ByVal value As String)
_filePath = value
End Set
End Property
Public Sub New(ByVal filename As String)
_filePath = filename
Dim _idx As Integer = 1
Dim fields As String()
Dim delimiter As String = ","
Dim iFnx As Integer
Using parser As New TextFieldParser(filename)
parser.SetDelimiters(delimiter)
While Not parser.EndOfData
' Read in the fields for the current line
fields = parser.ReadFields()
Try
iFnx = Convert.ToInt16(fields(0).ToString)
Catch ex As Exception
MessageBox.Show("Error reading file. " & ex.ToString, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
Exit Sub
End Try
Dim objFunction As New clsFunctionInfo
objFunction.IdxFunction = _idx
objFunction.IFunctionNumber = iFnx
objFunction.StrFunction = fields(1).ToString
Me.Add(objFunction)
_idx += 1
End While
End Using
End Sub
Public Function Add(ByVal value As Object) As Integer Implements System.Collections.IList.Add
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
SyncLock Me.SyncRoot
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End SyncLock
ReIndex()
End If
SyncLock Me.SyncRoot
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString)
End SyncLock
End Function
Public Sub Clear() Implements System.Collections.IList.Clear
SyncLock Me.SyncRoot
_colFunctionInfo.Clear()
End SyncLock
End Sub
Public Function Contains(ByVal value As Object) As Boolean Implements System.Collections.IList.Contains
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
Return True
Else
Return False
End If
End Function
Public ReadOnly Property Count() As Integer Implements System.Collections.ICollection.Count
Get
Return _colFunctionInfo.Count
End Get
End Property
Public ReadOnly Property IsReadOnly() As Boolean Implements System.Collections.IList.IsReadOnly
Get
Return False
End Get
End Property
Public Sub Remove(ByVal value As Object) Implements System.Collections.IList.Remove
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
SyncLock Me.SyncRoot
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End SyncLock
ReIndex()
End If
End Sub
Public Function GetEnumerator() As System.Collections.IEnumerator Implements System.Collections.IEnumerable.GetEnumerator
Return _colFunctionInfo.GetEnumerator
End Function
Public Sub Insert(ByVal index As Integer, ByVal value As Object) Implements System.Collections.IList.Insert
SyncLock Me.SyncRoot
If _colFunctionInfo.Contains(value.IFunctionNumber.ToString) Then
_colFunctionInfo.Remove(value.IFunctionNumber.ToString)
End If
If index < _colFunctionInfo.Count Then
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString, index - 1)
Else
_colFunctionInfo.Add(value, value.IFunctionNumber.ToString)
End If
End SyncLock
ReIndex()
End Sub
Public Sub RemoveAt(ByVal index As Integer) Implements System.Collections.IList.RemoveAt
SyncLock Me.SyncRoot
If _colFunctionInfo.Count <= index And index > 0 Then
_colFunctionInfo.Remove(index)
End If
End SyncLock
ReIndex()
End Sub
Private Sub ReIndex()
SyncLock Me.SyncRoot
Dim iReIndex As Integer = 1
Dim colTemp As New Collection
For Each obj As clsFunctionInfo In _colFunctionInfo
obj.IdxFunction = iReIndex
colTemp.Add(obj, obj.IFunctionNumber)
iReIndex += 1
Next
_colFunctionInfo.Clear()
For Each obj1 As clsFunctionInfo In colTemp
_colFunctionInfo.Add(obj1, obj1.IFunctionNumber.ToString)
Next
colTemp.Clear()
End SyncLock
End Sub
Public ReadOnly Property IsSynchronized() As Boolean Implements System.Collections.ICollection.IsSynchronized
Get
Return True
End Get
End Property
Public ReadOnly Property SyncRoot() As Object Implements System.Collections.ICollection.SyncRoot
Get
Dim _syncRoot As New Object
Return _syncRoot
End Get
End Property
Public ReadOnly Property IsFixedSize() As Boolean Implements System.Collections.IList.IsFixedSize
Get
Return False
End Get
End Property
Public Sub CopyTo(ByVal array As System.Array, ByVal index As Integer) Implements System.Collections.ICollection.CopyTo
For Each obj As clsFunctionInfo In _colFunctionInfo
array(index) = obj
index += 1
Next
End Sub
Public Function IndexOf(ByVal value As Object) As Integer Implements System.Collections.IList.IndexOf
SyncLock Me.SyncRoot
Dim tmpFnInfo As New clsFunctionInfo
Dim tmpFunctionNumber As Integer
Dim tmpidx As Integer = -1
tmpFnInfo = DirectCast(value, clsFunctionInfo)
tmpFunctionNumber = tmpFnInfo.IFunctionNumber
For Each obj In _colFunctionInfo
tmpFnInfo = DirectCast(obj, clsFunctionInfo)
If tmpFunctionNumber = tmpFnInfo.IFunctionNumber Then
tmpidx = tmpFnInfo.IdxFunction
Exit For
End If
Next
Return tmpidx
End SyncLock
End Function
Default Public Property Item(ByVal index As Integer) As Object Implements System.Collections.IList.Item
Get
index += 1
Return _colFunctionInfo(index)
End Get
Set(ByVal value As Object)
End Set
End Property
End Class
I'm sorry that this is so long, but I know that someone on here has some great suggestions on how to handle this because I'm having a little trouble wrapping my head around it. I think I've been starring at it too long.
since you have the text file as an embedded resource, you can open a stream to the file from there, without having to write it to disk. The ResourceReader class should help you.

Do local variables in shared method work like static variable in C?

Will the list in this shared method keep its state throughout the life of the method? Or will a new list be created every time this method is called?
Protected Shared Function newResxNodes(ByVal newName As String, ByVal newValue As String, Optional ByVal newComment As String = "") As List(Of ResXDataNode)
Dim newResxNodesList As List(Of ResXDataNode) = New List(Of ResXDataNode)
Dim newResxNode As ResXDataNode = New ResXDataNode(newName, newValue)
If newComment <> String.Empty Then
newResxNode.Comment = newComment
End If
newResxNodesList.Add(newResxNode)
Return newResxNodesList
End Function
No, It does not work like static variables in C. It will be a new list for every call. If you want to retain the list and list items, create a shared class field.
I've done a test and it returns 3 lines.
Module Module1
Class b
Public Sub New()
Console.WriteLine("New")
End Sub
End Class
Class a
Public Shared Sub Test()
Dim c As b = New b
End Sub
End Class
Sub Main()
a.Test()
a.Test()
a.Test()
Console.ReadLine()
End Sub
End Module