2011-05-12 72 views
1

我想要做的是允许用户在文本框中编写一个方法,并让我的代码调用该方法。给定目标函数,这最终将用于演示小程序中进行优化。C#编译用户提供的代码和使用

所以我一直在使用示例控制台应用程序,但我遇到了麻烦。我已经检查了堆栈溢出和codeproject以及其他来源,并且已经到了可以编译代码的地步。但我迷失在如何调用它,只能访问一个方法。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 
using System.Reflection; 

namespace CodeCompilerTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"); 

      CompilerParameters parameters = new CompilerParameters(); 
      //parameters.GenerateExecutable = false; 
      parameters.GenerateInMemory = true; 
      //parameters.OutputAssembly = "Output.dll"; 

      string SourceString = @" 
            using System; 
            using System.Collections.Generic; 
            using System.Text; 

            namespace testone 
            { 
             public class myclass 
             { 
              public double Main() 
              { 
               return testd(5,8); 
              } 

              public double testd(double a, double b) 
              { 
               return a+b; 
              } 
             } 
            }"; 

      CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString); 

      if (results.Errors.Count > 0) 
      { 
       foreach (CompilerError CompErr in results.Errors) 
       { 
        Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";"); 
       } 
       Console.ReadLine(); 
      } 

      Assembly mAssembly = results.CompiledAssembly; 
      Type scripttype = mAssembly.GetType("myclass"); 
      Object rslt = new Object(); 
      Object[] argin = {5, 8}; 
      //rslt = scripttype.GetMethod("Main").Invoke(null, null); 
      rslt = scripttype.InvokeMember("Main", BindingFlags.InvokeMethod | BindingFlags.Public |BindingFlags.Static, null, null, null); 
      Console.WriteLine(((double)rslt).ToString()); 
      Console.ReadLine(); 
     } 
    } 
} 

我试过不同的组合,关于如何在方法上调用Invoke并不断收到错误。 我希望能够做的是让用户像这样定义一个函数:

public double funcname(double x, double y) 
{ 
    return x+y; 
} 

然后我可以直接调用funcname的。 如果这是不可行的,我会采取我现在可以得到的。

任何帮助或指导,将不胜感激。 谢谢。

回答

1

您需要在GetType调用中包含名称空间。
(或从源代码中删除名称空间)

您可能更愿意致电GetTypes()并查看程序集中定义的所有类型。

+0

工作,这样可以让我打电话给使用Invoke方法的功能。你知道一种叫做“testd(5,8)”的方法吗?最终的希望是用户提供的函数作为dll的代表。 – 2011-05-12 16:22:14

+0

另一个有用的资源,或多或少说同一件事:http://stackoverflow.com/questions/1698870/accessing-class-and-function-after-compiling-compiledassembly – 2011-05-12 16:23:03

+0

@Tim:调用'GetTypes()'并找到一种具有您正在寻找的功能的类型。 – SLaks 2011-05-12 16:25:10

1

我相信这篇文章将帮助您直接通过使用接口 http://www.codeproject.com/Articles/26312/Dynamic-Code-Integration-with-CodeDom

也许下面的访问方法是没有直接关系到你的要求,但我相信,你需要使用激活创建的实例该类,所以你可以调用testd方法 我的意思是你定义的代码没有对象,只是类的定义。
此外,我用GetTypes()[0]因为GetType()并没有为我

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.CodeDom.Compiler; 
using Microsoft.CSharp; 
using System.Reflection; 

namespace CodeCompilerTest 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      CodeDomProvider codeProvider = CodeDomProvider.CreateProvider("CSharp"); 

      CompilerParameters parameters = new CompilerParameters(); 
      //parameters.GenerateExecutable = false; 
      parameters.GenerateInMemory = true; 
      //parameters.OutputAssembly = "Output.dll"; 

      string SourceString = @" 
            using System; 
            using System.Collections.Generic; 
            using System.Text; 

            namespace testone 
            { 
             public class myclass 
             { 
              public double testd(double a, double b) 
              { 
               return a+b; 
              } 
             } 
            }"; 

      CompilerResults results = codeProvider.CompileAssemblyFromSource(parameters, SourceString); 

      if (results.Errors.Count > 0) 
      { 
       foreach (CompilerError CompErr in results.Errors) 
       { 
        Console.WriteLine("Line number " + CompErr.Line + ", Error Number: " + CompErr.ErrorNumber + ", '" + CompErr.ErrorText + ";"); 
       } 
       Console.ReadLine(); 
      } 

      Assembly mAssembly = results.CompiledAssembly; 
      Type scripttype = mAssembly.GetTypes()[0]; 
      Object myObject = Activator.CreateInstance(scripttype); 
      double rsltd = 0.0; 
      Object[] argin = { 5.0, 8.0 }; 
      rsltd =(double) scripttype.GetMethod("testd").Invoke(myObject,argin); 
      // object rslt = new object(); 
      // rslt = scripttype.InvokeMember("testd", BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static, null, null, null); 
     Console.WriteLine(rsltd.ToString()); 
     Console.ReadLine(); 
     } 
    } 
}