VB.Net:使用参数动态调用模块Method或Routine

时间:2016-09-20 18:21:13

标签: vb.net string methods module

我想使用变量名称运行一个方法,该方法存储在带有参数的模块中:

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

我不想使用Select Case,因为这些方法在许多不同的模块中,我不想维护一个选择案例函数。

我查了CallByName但似乎这只适用于Classes。在模块时,我无法弄清楚如何设置对象ObjectRef

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

有没有办法在VB.Net中执行此操作?

编辑:为了使它变得非常简单,我需要相当于VBA:

Application.Run module_name.sub_name param

2 个答案:

答案 0 :(得分:1)

您可以使用反射来创建Module中方法的委托。我会将创建的代理加载到Dictionary(Of String, Action(Of Int32))

选择

Action(Of Int32)是因为它匹配您使用整数参数指定的子程序的签名。

假设您的Module定义如下:

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

现在创建代表并将其存储在字典中。

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

您可以像这样检索和调用委托:

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

编辑:我有时会让事情变得复杂。 LoadMethods方法可以在没有这样反映的情况下完成:

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

编辑2:根据下面的编辑问题和评论。

  

编辑:为了使它变得非常简单,我需要相当于VBA&#39;

     

Application.Run module_name.sub_name param

您需要首先根据输入的名称从其包含的程序集中提取Module类型。然后,您可以检索MethodInfo,如上所示。以下示例假定模块包含在正在执行的程序集中,并且实现了最少的检查。它将要求您提供模块名称,方法名称和数组正确键入的方法参数。在现实世界中,可能需要使用一串参数并执行某种类型的动态类型转换,以基于调用MethodInfo.GetParameters来构建typedArgs数组。

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

使用示例:Exec("SomeModule", "Sub1", New Object() {123})

答案 1 :(得分:0)

假设你想调用子程序(或函数)sub1,参数123,可选的给定模块名称module1

调用示例,如果模块名称不可用(要调用的函数名称在项目中应该是唯一的):

requests

或者,如果您知道模块名称:

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

InvokeModuleFunction 定义

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

或者,您可以在调用中使用多个参数。 您需要修改上述函数以允许传递多个参数。 调用部分看起来像:

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