【问题标题】:c# execute a string as codec# 将字符串作为代码执行
【发布时间】:2009-10-02 19:30:38
【问题描述】:

这是我想要做的,我知道使用 perl、php、python 和 java 是可能的,但我正在使用 c#

我该怎么做:

public void amethod(string functionName)
{
    AVeryLargeWebServiceWithLotsOfMethodsToCall.getFunctionName();
}

我想将 functionName 传递给方法,并希望它按上述方式执行。

如何做到这一点?

我需要 ANTLR 或任何其他工具吗?

谢谢。

【问题讨论】:

  • 我最终放弃了几年来编写的代码,因此我不会为答案而烦恼。但是,您确实可以在 C# 中运行动态构造的代码。您不需要任何额外的工具 - 它内置于 .NET 框架中。
  • 执行字符串作为代码与通过选择方法名称执行现有方法有很大不同。

标签: c# .net web-services read-eval-print-loop


【解决方案1】:

您可以通过反射按名称执行方法。您需要知道类型以及方法名称(可以是当前对象的类型,或者不同对象上的方法,或者静态类型)。看起来你想要这样的东西:

public void amethod(string functionName) 
{
    Type type = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall);
    MethodInfo method = type.GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
    method.Invoke(null,null); // Static methods, with no parameters
}

根据评论进行编辑:

听起来你实际上想从这个方法中得到一个结果。如果是这种情况,考虑到它仍然是服务上的静态方法(这是我的猜测,考虑到你写的内容),你可以这样做。 MethodInfo.Invoke 将直接将方法的返回值作为对象返回,因此,例如,如果您要返回一个字符串,则可以这样做:

public string amethod(string functionName) 
{
    Type type = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall);
    MethodInfo method = type.GetMethod(functionName, BindingFlags.Public | BindingFlags.Static);
    object result = method.Invoke(null,null); // Static methods, with no parameters
    if (result == null)
        return string.Empty;
    return result.ToString();
    // Could also be return (int)result;, if it was an integer (boxed to an object), etc.
}

【讨论】:

    【解决方案2】:

    在 c# 中可以像执行代码一样执行字符串,但这并不漂亮或简单。它也被认为是不好的做法和不安全的(你可能也应该在动态语言中避免它)。

    相反,请执行以下操作:

    public void amethod(Action actionParam)
    {
        actionParam();
    }
    

    现在,在您的情况下,您想调用 Web 服务。因为这最终归结为 xml,所以你有几个选择:

    • 绕过用于调用 Web 服务的内置系统,并在 xml 中的正确位置使用正确的名称创建您自己的 Web 请求。
    • 为服务中要传递的每个方法创建委托,可能通过反射。

    【讨论】:

    • “糟糕的实践和不安全” 你能解释一下原因吗?有几个框架使用这种范式,实际上使事情动态化。如果它是糟糕的实践和不安全的,那么什么是更好的实践和安全?
    • 执行用户提交的任意代码是个坏主意。如果它是 your 字符串,并且您确定 sure 它是您的字符串,那是一回事。但最好确定这一点。您在这里谈论的是一种全新的安全漏洞类别,类似于 sql 注入。仅仅因为很多动态程序都这样做并不能使它正确。
    • 明白。是的,我很确定 :) 没有人可以访问它,仅供内部使用。谢谢。
    【解决方案3】:

    您是说AVeryLargeWebServiceWithLotsOfMethodsToCall 是一个对象的实例,您要在该对象上调用名为functionName 的方法吗?如果是这样:

    MethodInfo method = AVeryLargeWebServiceWithLotsOfMethodsToCall.GetType().GetMethod(functionName);
    method.Invoke(AVeryLargerWebServiceWithLotsOfMethodsToCall, null);
    

    或者AVeryLargeWebServiceWithLotsOfMethodsToCall 是您想要调用名为functionName 的静态方法的类型?如果是这样:

    MethodInfo method = typeof(AVeryLargeWebServiceWithLotsOfMethodsToCall).GetMethod(functionName);
    method.Invoke(null, null);
    

    【讨论】:

      【解决方案4】:

      可以使用反射来完成。但是,我相信您需要一个对象引用才能使用它。

      来自here的示例

      Type t = this.GetType();
      MethodInfo method = t.GetMethod("showMessage");
      method.Invoke(this, null);
      

      或者,您可以使用Action 或其他一些委托来传递对您要调用的函数的引用。

      public void amethod(Action function)
      {
          function();
      }
      

      【讨论】:

        【解决方案5】:

        为什么不直接使用 .NET Remoting?它就是为此而生的。

        一个完全其他的解决方案是使用 CSharpCodeCompiler 类。

        【讨论】:

          【解决方案6】:

          这里有几个实用方法,它们可以处理作为字符串传入的类和实例方法调用,带有可选的 args 和 varargs。

          这不是生产代码。至少对于这些琐碎的例子来说,它似乎有效。

          class Program
          {
              static void Main(string[] args)
              {
                  double alpha = Math.Sin(1.0);
                  int beta = alpha.CompareTo(1.0);
                  Console.WriteLine("{0} {1}", alpha, beta);
          
                  double gamma = (double)CallClassMethod("System.Math.Sin", 1.0);
                  int delta = (int)CallInstanceMethod(gamma, "CompareTo", 1.0);
                  Console.WriteLine("{0} {1}", gamma, delta);
          
                  string a = "abc";
                  string x = "xyz";
                  string r = String.Join(",", a, x);
                  string s = r.Replace(",", ";");
                  Console.WriteLine("{0} {1}", r, s);
                  string t = (string)CallClassMethod("System.String.Join", ",", new String[] { a, x }); // Join takes varargs
                  string u = (string)CallInstanceMethod(t, "Replace", ",", ";");
                  Console.WriteLine("{0} {1}", t, u);
                  Console.ReadKey();
              }
          
              static object CallClassMethod(string command, params object[] args)
              {
                  Regex regex = new Regex(@"(.*)\.(\w*)");
                  Match match = regex.Match(command);
                  string className = match.Groups[1].Value;
                  string methodName = match.Groups[2].Value;
                  Type type = Type.GetType(className);
                  List<Type> argTypeList = new List<Type>();
                  foreach (object arg in args) { argTypeList.Add(arg.GetType()); }
                  Type[] argTypes = argTypeList.ToArray();
                  MethodInfo method = type.GetMethod(methodName, argTypes, null);
                  return method.Invoke(null, args);
              }
          
              static object CallInstanceMethod(object instance, string methodName, params object[] args)
              {
                  Type type = instance.GetType();
                  List<Type> argTypeList = new List<Type>();
                  foreach (object arg in args) { argTypeList.Add(arg.GetType()); }
                  Type[] argTypes = argTypeList.ToArray();
                  MethodInfo method = type.GetMethod(methodName, argTypes, null);
                  return method.Invoke(instance, args);
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2017-11-07
            • 2012-09-10
            • 1970-01-01
            • 2011-04-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多