我想使用变量名称运行一个方法,该方法存储在带有参数的模块中:
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
答案 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