2016-02-11 130 views
2

我已经成功使用本教程:http://www.codeproject.com/Tips/715891/Compiling-Csharp-Code-at-Runtime为运行时编译和C#代码的执行设置框架。下面是我目前拥有的代码:使用CSharpCodeProvider进行C#运行时编译

public static class CodeCompiler { 

public static object InterpretString(string executable) { 
    string compilation_string = 
    @" 
    static class RuntimeCompilationCode { 
     public static void Main() {} 
     public static object Custom() { 
      /* CODE HERE */ 
     } 
    }"; 

    compilation_string = compilation_string.Replace("/* CODE HERE */", executable); 

    CSharpCodeProvider provider = new CSharpCodeProvider(); 
    CompilerParameters compiler_parameters = new CompilerParameters(); 

    // True - memory generation, false - external file generation 
    compiler_parameters.GenerateInMemory = true; 

    // True - exe file generation, false - dll file generation 
    compiler_parameters.GenerateExecutable = true; 

    // Compile 
    CompilerResults results = provider.CompileAssemblyFromSource(compiler_parameters, compilation_string); 

    // Check errors 
    if (results.Errors.HasErrors) { 
     StringBuilder builder = new StringBuilder(); 
     foreach (CompilerError error in results.Errors) { 
      builder.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText)); 
     } 
     throw new InvalidOperationException(builder.ToString()); 
    } 

    // Execute 
    Assembly assembly = results.CompiledAssembly; 
    Type program = assembly.GetType("RuntimeCompilationCode"); 
    MethodInfo execute = program.GetMethod("Custom"); 
    return execute.Invoke(null, null); 
} 

} 

我可以在一个字符串(前"return 2;")到InterpretString()的形式通过一项声明,它会被编译并作为Custom()功能的一部分执行。不过,我想知道是否可以使用相同的方法来执行我的原始文件中的方法。例如,假设CodeCompiler类有另一种方法returnsTwo(),它返回整数2.有没有办法调用"CodeCompiler.returnsTwo();"或类似的字符串InterpretString()来调用这样的方法?

回答

3

只要函数是一个静态函数,只要您将相应的引用添加到编译中,这应该不成问题。我在几个项目上做了这件事。

如果CodeCompiler是在当前的可执行文件,你必须包括以这种方式引用:

string exePath = Assembly.GetExecutingAssembly().Location; 
string exeDir = Path.GetDirectoryName(exePath); 

AssemblyName[] assemRefs = Assembly.GetExecutingAssembly().GetReferencedAssemblies(); 
List<string> references = new List<string>(); 

foreach (AssemblyName assemblyName in assemRefs) 
    references.Add(assemblyName.Name + ".dll"); 

for (int i = 0; i < references.Count; i++) 
{ 
    string localName = Path.Combine(exeDir, references[i]); 

    if (File.Exists(localName)) 
     references[i] = localName; 
} 

references.Add(exePath); 

CompilerParameters compiler_parameters = new CompilerParameters(references.ToArray())