在.NET中基于字符串值创建方法调用
现在,我的代码看起来像这样:
Private Sub ShowReport(ByVal reportName As String) Select Case reportName Case "Security" Me.ShowSecurityReport() Case "Configuration" Me.ShowConfigurationReport() Case "RoleUsers" Me.ShowRoleUsersReport() Case Else pnlMessage.Visible = True litMessage.Text = "The report name """ + reportName + """ is invalid." End Select End Sub
有什么方法可以创建使用我的方法命名约定简化代码的代码?这是一些伪代码,描述了我要寻找的东西:
Private Sub ShowReport(ByVal reportName As String) Try Call("Show" + reportName + "Report") Catch ex As Exception 'method not found End Try End Sub
解决方案
我们可以使用反射来做到这一点,但老实说,我认为这会使特定情况变得过于复杂,即同一类中的代码和switch()。
现在,如果我们已设计应用程序以使其每种报告类型都在其自己的程序集中(类似于外接程序/插件体系结构)或者捆绑在单个外部程序集中,则可以将报告程序集加载到appdomain中,然后用反射来做这种事情。
我们可以使用" System.Reflection"。有关更多信息,请参见此代码项目文章。
string ModuleName = "TestAssembly.dll"; string TypeName = "TestClass"; string MethodName = "TestMethod"; Assembly myAssembly = Assembly.LoadFrom(ModuleName); BindingFlags flags = (BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); Module [] myModules = myAssembly.GetModules(); foreach (Module Mo in myModules) { if (Mo.Name == ModuleName) { Type[] myTypes = Mo.GetTypes(); foreach (Type Ty in myTypes) { if (Ty.Name == TypeName) { MethodInfo[] myMethodInfo = Ty.GetMethods(flags); foreach(MethodInfo Mi in myMethodInfo) { if (Mi.Name == MethodName) { Object obj = Activator.CreateInstance(Ty); Object response = Mi.Invoke(obj, null); } } } } } }
使用反射。在System.Reflection命名空间中,我们需要为包含所需方法的类型使用GetMethod(" methodName")来获取所需方法的MethodMethod对象。
一旦有了MethodInfo对象,就可以使用对象实例和任何参数调用.Invoke()
。
例如:
System.Reflection.MethodInfo method = this.GetType().GetMethod("foo"); method.Invoke(this, null);
Type type = GetType(); MethodInfo method = type.GetMethod("Show"+reportName+"Report"); if (method != null) { method.Invoke(this, null); }
这是C#,应该足够容易才能将其转换为VB。如果需要将参数传递给方法,则可以将它们添加到Invoke的第二个参数中。
Reflection API允许我们从方法中获取MethodInfo
,然后在其上动态调用Invoke
。但这对你来说太过分了。
我们应该考虑使用由字符串索引的代表字典。
Python(和IronPython)可以很容易地做到这一点。但是,使用.Net时,我们需要使用反射。
在C#中:http://www.dotnetspider.com/resources/4634-Invoke-me-ods-dynamically-using-reflection.aspx
我对VB.Net的快速移植:
Private Sub InvokeMethod(instance as object, methodName as string ) 'Getting the method information using the method info class Dim mi as MethodInfo = instance.GetType().GetMethod(methodName) 'invoing the method 'null- no parameter for the function [or] we can pass the array of parameters mi.Invoke(instance, Nothing) End Sub
我们可以使用反射。尽管个人而言,我认为我们应该坚持使用switch语句。
private void ShowReport(string methodName) { Type type = this.GetType(); MethodInfo method = type.GetMethod("Show"+methodName+"Report", BindingFlags.Public) method.Invoke(this, null); }
抱歉,我在做C#。只需将其翻译为VB.NET。
如果我正确理解了这个问题,则必须使用Reflection找到方法" show" + reportName,然后间接调用它:
半生半熟的例子:
Case "financial" : { Assembly asm = Assembly.GetExecutingAssembly (); MethodInfo mi = asm.GetType ("thisClassType").GetMethod ("showFinancialReport"); if (mi != null) mi.Invoke (null, new object[] {}); }
在其中插入我们自己的逻辑,以组成要调用的方法的名称。
有关详细信息,请参见MethodInfo和Assembly的MSDN文档。
使用反射:
Type t = this.GetType(); try { MethodInfo mi = t.GetMethod(methodName, ...); if (mi != null) { mi.Invoke(this, parameters); } }
但我同意,最好不要更改原始代码;-)
我们有一个更深层次的问题。字符串太重要了。谁在传递你的琴弦?你可以让他们不这样做吗?
坚持使用switch语句,因为它使内部实现(方法名称)与外部视图脱钩。
假设我们将此语言本地化为德语。我们要重命名所有这些方法吗?
"最接近问题"解决方案。
我们可以从这些报告中挑选出代表,然后通过在哈希表中查找匹配的String来调用它们:
Public Sub New() '... ReportTable.Add("Security", New ReportDelegate(AddressOf ShowSecurityReport)) ReportTable.Add("Config", New ReportDelegate(AddressOf ShowConfigReport)) ReportTable.Add("RoleUsers", New ReportDelegate(AddressOf ShowRoleUsersReport)) '... End Sub Private Sub ShowSecurityReport() '... End Sub Private Sub ShowConfigReport() '... End Sub Private Sub ShowRoleUsersReport() '... End Sub Private Delegate Sub ReportDelegate() Private ReportTable As New Dictionary(Of String, ReportDelegate) Private Sub ShowReport(ByVal reportName As String) Dim ReportToRun As ReportDelegate If ReportTable.TryGetValue(reportName, ReportToRun) Then ReportToRun() Else pnlMessage.Visible = True litMessage.Text = "The report name """ + reportName + """ is invalid." End If End Sub
这样,我们可以添加任意数量的报告,而我们反映它们的能力以及反射的成功率就不成问题了。