1

I want to run a Method using a variable name that is stored in a Module with a parameter:

Dim subName as String = "sub1"
Dim param as Integer = 123
sub1(param) <- I want to run this using the **subName** string

I don't want to use Select Case because the Methods are in many different modules and I don't want to maintain a select-case function.

I looked up CallByName but it seems this only works for Classes. I can't figure out how to set the object ObjectRef when it comes to Modules :

Public Function CallByName(ByVal ObjectRef As System.Object,ByVal ProcName As String,ByVal UseCallType As CallType, ByVal Args() As Object) As Object

Is there a way to do this in VB.Net?

Edit: To make it really simple, I need the equivalent of VBA's:

Application.Run module_name.sub_name param
0

2 Answers 2

1

You can use reflection to create a delegate to the methods in the Module. I would load the created delegates into a Dictionary(Of String, Action(Of Int32)).

Action(Of Int32) is chosen because it matches the signature you specified of a subroutine taking an integer parameter.

Assume you have a Module defined like this:

Module SomeModule
    Public Sub Sub1(arg As Int32)
        Console.WriteLine("Sub1: {0}", arg)
    End Sub
    Public Sub Sub2(arg As Int32)
        Console.WriteLine("Sub2: {0}", arg)
    End Sub
End Module

Now to create and store the delegates in a dictionary.

Private methods As New Dictionary(Of String, Action(Of Int32))
Sub LoadMethods()
    Dim modType As Type = GetType(SomeModule)
    Dim mi As Reflection.MethodInfo
    mi = modType.GetMethod("Sub1", BindingFlags.Static Or BindingFlags.Public)
    methods.Add(mi.Name, CType(mi.CreateDelegate(GetType(Action(Of Int32))), Action(Of Int32)))

    mi = modType.GetMethod("Sub2", BindingFlags.Static Or BindingFlags.Public)
    methods.Add(mi.Name, CType(mi.CreateDelegate(GetType(Action(Of Int32))), Action(Of Int32)))
End Sub

You can retrieve and invoke the delegate like this:

methods("Sub1")(123)
methods("Sub2")(456)

Edit: I sometimes makes things to complicated. The LoadMethods method can be done without reflection like this:

Sub LoadMethods()
    methods.Add("Sub1", New Action(Of Int32)(AddressOf SomeModule.Sub1))
    methods.Add("Sub2", New Action(Of Int32)(AddressOf SomeModule.Sub1))
End Sub

Edit 2: Based on edit to question and comment below.

Edit: To make it really simple, I need the equivalent of VBA's:

Application.Run module_name.sub_name param

You will need to first extract the Module type from its containing assembly based on the entered name. Then you can retrieve the MethodInfo as shown above. The following example assumes that the module is contained in the executing assembly and has minimal checks implemented. It will require you to provide the module name, method name and an array properly typed method arguments. In a real world scenario, it would probably need to take a string of the arguments and perform some type of dynamic type casting to build up the typedArgs array based on calling MethodInfo.GetParameters.

Private Shared Sub Exec(moduleName As String, methodName As String, typedArgs As Object())
    Dim asm As Reflection.Assembly = Assembly.GetExecutingAssembly
    Dim modType As Type = asm.GetType(String.Format("{0}.{1}", asm.GetName.Name, moduleName))
    If modType IsNot Nothing Then
        Dim mi As Reflection.MethodInfo
        mi = modType.GetMethod(methodName, BindingFlags.Static Or BindingFlags.Public)
        If mi IsNot Nothing Then
            mi.Invoke(Nothing, typedArgs)
        End If
    End If
End Sub

Example usage: Exec("SomeModule", "Sub1", New Object() {123})

Sign up to request clarification or add additional context in comments.

3 Comments

Thanks, but this requires that I add every new Sub and every new module to LoadMethods (i dont want maintenance). I want the VB.Net equivalent of VBA: Application.Run module_name.sub_name param
@BassemLhm, I provided a basic template for accomplishing your modified requirement as an edit to this answer.
Thanks so much. Only thing I changed was to replace spaces with underscore in asm.GetName.Name ...
0

Lets say you want to call subroutine (or function) sub1 with parameter 123 with optionally given module name module1

Call example, If module name is not available (function name to invoke should be unique among project):

Dim FunctionName As String = "sub1"
Dim Param As Integer = 123
InvokeModuleFunction(FunctionNameToCall:=FunctionName, FunctionParameters:=Param)

Alternatively, If you know module name:

Dim FunctionName As String = "sub1"
Dim Param As Integer = 123    
Dim ModuleName As String = "module1"
InvokeModuleFunction(FunctionNameToCall:=FileType, ModuleName:=ModuleName, FunctionParameters:=Param)

InvokeModuleFunction definition

Private Sub InvokeModuleFunction(FunctionNameToCall As String, FunctionParameters As Object, Optional ModuleName As String = Nothing)
    Dim MyReflectionAssembly = Reflection.Assembly.GetExecutingAssembly()

    Dim MyFunctionType As Type
    If IsNothing(ModuleName) Then
        'Gets function without ModuleName. FunctionName should be unique in the assembly/programm.
        MyFunctionType = MyReflectionAssembly.DefinedTypes.Where(Function(x) x.DeclaredMethods.Where(Function(y) y.Name = FunctionNameToCall).Count > 0).FirstOrDefault
    Else
        'Gets function using ModuleName, if available
        MyFunctionType = MyReflectionAssembly.DefinedTypes.Where(Function(x) x.Name = ModuleName AndAlso x.DeclaredMethods.Where(Function(y) y.Name = FunctionNameToCall).Count > 0).FirstOrDefault
    End If

    If Not IsNothing(MyFunctionType) Then MyFunctionType.GetMethod(FunctionNameToCall).Invoke(MyFunctionType, New Object() {FunctionParameters})
End Sub

Alternatively you can use more than one parameter in invoking. You would need to modify the above function to allow to pass more than one parameter. The invoke part would look like:

FunctionType.GetMethod(FunctionNameToCall).Invoke(FunctionType, New Object() {Par1, Par2, Par3})

1 Comment

While this code snippet may solve the problem, it doesn't explain why or how it answers the question. Please include an explanation for your code, as that really helps to improve the quality of your post. Remember that you are answering the question for readers in the future, and those people might not know the reasons for your code suggestion. You can use the edit button to improve this answer to get more votes and reputation!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.