2016-09-20 50 views
0

,呼叫模块方法或例程动态我想运行使用变量名存储在一个模块带有参数的方法:VB.Net:与参数

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

我不不想使用SelectCase,因为这些方法在很多不同的模块中,我不想维护一个select-case函数。

我抬头看CallByName但似乎这只适用于类。我无法弄清楚如何设置对象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 

回答

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的等价的:

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})

+0

谢谢,但是这需要我添加的每个新Sub和每一个新的模块LoadMethods(我不想维护)。我希望VB.Net等价于VBA:Application.Run module_name.sub_name参数 –

+0

@BassemLhm,我提供了一个基本模板来完成修改的需求,作为对此答案的编辑。 – TnTinMn

+0

非常感谢。唯一改变的是用asm.GetName.Name中的下划线替换空格... –