0

How can the multiple subs from a module can be called in a For loop in VB.NET?

My code is:

Private Sub BtnLog_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnLog.Click
    Dim LoggerString As String
    For i = 1 To 5
        LoggerString = "DataLoggerCh" & i & "()"
        Call LoggerString.ToString()
    Next
End Sub

The Subs DataLoggerCh1 to DataLoggerCh5 are a part of module as below:

Module ModuleLogger
Sub DataLoggerCh1()
    myConnection.ConnectionString = connstring
    myConnection.Open()
    Dim InsertString As String
    InsertString = "Insert into Table_Channel1 ([Log_Date],[Log_Time],[Test_Desc],[Current_1],[Current_2])values(?,?,?,?,?)"

    Dim cmd As OleDbCommand = New OleDbCommand(InsertString, myConnection)

    cmd.Parameters.Add(New OleDbParameter("Log_Date", CType(Today(), Date)))
    cmd.Parameters.Add(New OleDbParameter("Log_Time", CType(TimeOfDay(), String)))
    cmd.Parameters.Add(New OleDbParameter("Test_Desc", FormMain.Test_Desc_Ch1))
    cmd.Parameters.Add(New OleDbParameter("Current_1", LoggerValCh1(0)))
    cmd.Parameters.Add(New OleDbParameter("Current_2", LoggerValCh1(1)))

    Try
        cmd.ExecuteNonQuery()
        cmd.Dispose()
        myConnection.Close()

    Catch ex As Exception
        MsgBox(ex.Message)
        myConnection.Close()
    End Try
End Sub
End Module

But when I click Button, the respective subs are not getting called.

How can it be achieved?.

Prashant
  • 93
  • 9

3 Answers3

2

That's the wrong approach(you would need reflection but forget it immediately). Instead provide only one method with a parameter, for example:

Private Sub BtnLog_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnLog.Click
    For i = 1 To 5
        SaveChannelLog(i)
    Next
End Sub

How does this solve your issue? It does not. You need to refactor other things as well. I suggest to implement a custom class that encapsulates all nessesary informations, like this:

Public Class LoggerInfo
    Public Sub New(tableName As String, description As String, loggerValCh As List(Of Int32))
        Me.New(tableName, description, DateTime.Now, loggerValCh)
    End Sub
    Public Sub New(tableName As String, description As String, logTime As DateTime, loggerValCh As List(Of Int32))
        Me.TableName = tableName
        Me.Description = description
        Me.LoggerValCh = loggerValCh
        Me.LogTime = DateTime.Now
    End Sub

    Public Property LoggerValCh As List(Of Int32)
    Public Property TableName As String
    Public Property LogTime As DateTime ' you don't need LogDate because you get it via LogTime.Date
    Public Property Description As String
End Class

(class can be extended by other properties or methods ...)

Now you can store instances of this class in a collection that is accessible by the channel number, for example a Dictionary(Of Int32, LoggerInfo). A sample initialization:

Public Property ChannelLoggers As New Dictionary(Of Int32, LoggerInfo) From {
    {1, New LoggerInfo("Table_Channel1", "Channel 1 Logger", New List(Of Int32))},
    {2, New LoggerInfo("Table_Channel2", "Channel 2 Logger", New List(Of Int32))}
 }

You should set the LoggerValCh-values somewhere in your code, you can access them via this property. Then you have everything you need to write a single, clean and readable method:

Sub SaveChannelLog(channel As Int32)
    Dim loggerInfo As LoggerInfo = Nothing
    Dim validChannel = ChannelLoggers.TryGetValue(channel, loggerInfo)
    If Not validChannel Then
        'log this and return ...'
        Return
    End If

    Dim sql = $"Insert into {loggerInfo.TableName}([Log_Date],[Log_Time],[Test_Desc],[Current_1],[Current_2])values(?,?,?,?,?)"

    Using con As New OleDbConnection("your connection string here")
        Using cmd As New OleDbCommand(sql, con)
            cmd.Parameters.Add(New OleDbParameter("Log_Date", OleDbType.Date)).Value = loggerInfo.LogTime.Date
            cmd.Parameters.Add(New OleDbParameter("Log_Time", OleDbType.Date)).Value = loggerInfo.LogTime
            cmd.Parameters.Add(New OleDbParameter("Test_Desc", OleDbType.VarChar)).Value = loggerInfo.Description
            cmd.Parameters.Add(New OleDbParameter("Current_1", OleDbType.Integer)).Value = loggerInfo.LoggerValCh(0)
            cmd.Parameters.Add(New OleDbParameter("Current_2", OleDbType.Integer)).Value = loggerInfo.LoggerValCh(1)
            con.Open()
            Dim numInserted = cmd.ExecuteNonQuery()
        End Using
    End Using
End Sub

I have used the Using-statement for the connection which is recommended for various reasons.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • The question was "Calling multiple subs in for For Loop" not "How can i clean up this code". However, i hope your answer is seen as motivation to do just that and keep code clean. – Detonar Nov 21 '17 at 10:02
  • When `Calling multiple subs in for For Loop` is obvious the worst solution based on design, readability, maintainability, ... a clean-code answer is always to be prefered. This should be the accepted answer since it is well written and addresses problems which will come up in the future. – Alex B. Nov 22 '17 at 11:30
1

If they all have the same signature you can write them into an array of delegates and iterate through it.

Try something like this

private Delegate Sub DelegateDataLogger
private dataLogger as DelegateDataLogger() = {addressof DataLoggerCh1, addressof DataLoggerCh2, ...}

Private Sub BtnLog_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnLog.Click
    For i = 1 To dataLogger.length-1 step 1
        dataLogger(i).Invoke()

    Next
End Sub
Detonar
  • 1,409
  • 6
  • 18
1

I would do this:

Private Sub BtnLog_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) 'Handles BtnLog.Click
    Dim Logger() As Action = _
        { _
            AddressOf DataLoggerCh1, AddressOf DataLoggerCh2, AddressOf DataLoggerCh3, _
            AddressOf DataLoggerCh4, AddressOf DataLoggerCh5 _
        }
    For i = 1 To 5
        Logger(i - 1).Invoke()
    Next
End Sub

But, then again, just calling each of the methods would be cleaner.

Enigmativity
  • 113,464
  • 11
  • 89
  • 172