【问题标题】:Create a method call in .NET based on a string value基于字符串值在 .NET 中创建方法调用
【发布时间】:2008-09-25 16:03:51
【问题描述】:

现在,我的代码看起来像这样:

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

【问题讨论】:

  • 你确定用字符串重写任何调用你的函数不会更容易吗?
  • 你可以用反射来做类似的事情,但我认为你的代码会更难看。你会有多少这样的?我认为您最好使用某种形式的命令模式,其中您的枚举字符串是命令的名称!
  • 非常正确。我认为我们正在寻找好的方法来构建一些不太好的东西。
  • 我不确定你用字符串重写的意思。
  • 如果方法的数量至少超过 20..30,反射将是一个好的解决方案。

标签: .net vb.net method-call


【解决方案1】:
Type type = GetType();
MethodInfo method = type.GetMethod("Show"+reportName+"Report");
if (method != null)
{
    method.Invoke(this, null);
}

这是 C#,应该很容易将其转换为 VB。如果您需要将参数传递给方法,可以将它们添加到 Invoke 的第二个参数中。

【讨论】:

  • 没有开车经过,只是观察这里的东西闻起来不太香。见stackoverflow.com/questions/134214/…。为什么是字符串?是用户输入吗?可以完全避免这个问题吗?应该吗?
【解决方案2】:

你有一个更深层次的问题。你的琴弦太重要了。谁在给你传递字符串?你能让他们不要那样做吗?

坚持使用 switch 语句,因为它将您的内部实现(方法名称)与您的外部视图分离。

假设您将其本地化为德语。你要重命名所有这些方法吗?

【讨论】:

    【解决方案3】:

    反射 API 允许您从方法中获取 MethodInfo,然后在其上动态调用 Invoke。但在你的情况下它是矫枉过正的。

    您应该考虑拥有一个按字符串索引的委托字典。

    【讨论】:

    • 介意展示一个如何实现一个由字符串索引的委托字典并调用方法的例子吗?
    【解决方案4】:

    您可以使用反射来做到这一点,但老实说,我认为这对于您的特定场景来说过于复杂了,即同一类中的代码和 switch()。

    现在,如果您将应用设计为在自己的程序集中包含每种报告类型(有点像插件/插件架构)或捆绑在单个外部程序集中,那么您可以将报告程序集加载到appdomain 然后使用反射来做这种事情。

    【讨论】:

      【解决方案5】:

      使用反射。在System.Reflection 命名空间中,您需要为您想要的方法获取一个MethodInfo 对象,在包含该方法的类型上使用GetMethod("methodName")

      拥有MethodInfo 对象后,您可以使用对象实例和任何参数调用.Invoke()

      例如:

      System.Reflection.MethodInfo method = this.GetType().GetMethod("foo");
      method.Invoke(this, null);
      

      【讨论】:

        【解决方案6】:

        您可以使用反射。尽管就个人而言,我认为您应该坚持使用 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。

        【讨论】:

        • 如果方法返回一些东西会存储在哪里??
        • 调用返回一个对象。只需将其转换为适当的类型即可。
        【解决方案7】:

        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
        

        【讨论】:

          【解决方案8】:

          如果我正确理解了这个问题,您将不得不使用反射找到方法“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 文档。

          【讨论】:

            【解决方案9】:

            使用反射:

            Type t = this.GetType();
            try 
            {
                MethodInfo mi = t.GetMethod(methodName, ...);
            
                if (mi != null)
                {
                    mi.Invoke(this, parameters);
                }
            } 
            

            但我同意之前,最好不要更改您的原始代码;-)

            【讨论】:

              【解决方案10】:

              “最接近您的问题”的解决方案。

              您可以从这些报告中创建代表,并通过在 Hashtable 中查找匹配的字符串来调用它们:

              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
              

              通过这种方式,您可以添加任意数量的报告,并且您反映它们的能力以及反映的效果都不是问题。

              【讨论】:

                【解决方案11】:

                您可以使用System.Reflection。有关更多信息,请参阅this code project article

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

                【讨论】:

                  【解决方案12】:

                  在 VB .Net MSVS 2015 中为我工作

                  Dim tip As Type = GetType(MODULENAME)'if sub() or function() in module
                          Dim method As MethodInfo = tip.GetMethod("MaxV") 'name of function (gets 2 params double type)
                          Dim res As Double = 0 'temporary variable
                          If (Not Nothing = method) Then 'if found function "MaxV"
                  
                              res = method.Invoke(Me, New Object() {10, 20})
                          End If
                          MsgBox(res.ToString())
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2019-06-05
                    • 1970-01-01
                    • 1970-01-01
                    相关资源
                    最近更新 更多