C#CompilerResults GenerateInMemory?

我一直在关注这个StackOverflow问题 。 它是我能找到的最接近的东西,但并不完全。

让我解释一下我的最终目标是在我的问题之前,我正在制作一个支持web的编译器平台,因此,我想在内存中做所有事情( 不做任何文件 ),所以我希望能够编译代码,然后能够引用我刚刚编译的类中的对象进行任意测试。 我知道它听起来有多安全,所以欢迎提供安全方面的意见。

我的问题是如何将C#源代码编译到内存中,并创建该类的实例?

目前我正处于一个步骤,我可以生成有效的.dll并导入并在VisualStudio中手动使用它。

接下来的两个步骤是:

  • 自动加载程序集( 这就是我在这里要求的
    • 这意味着我不再需要为dll提供路径,并手动获取封闭类的成员
  • 任意引用它的成员
    • 这意味着我可以创建一个类的接口,而无需其成员的先验知识,有点像foreach循环如何在键值对上工作。

为了完全在记忆中尝试这个,我试过这个。 (来源然后解释)

private object sourceToObj(string source) { string source = "..."; /*my class*/ CSharpCodeProvider pro = new CSharpCodeProvider(); CompilerParameters params = new CompilerParameters(); params.GenerateInMemory = true; params.GenerateExecutable = false; params.ReferencedAssemblies.Add("System.dll"); CompilerResults res = pro.CompileAssemblyFromSource( params, source ); Assembly DOTasm = res.CompiledAssembly; AppDomain domain = AppDomain.CreateDomain( "thisdomain" ); domain.load( DOTasm , /*???*/ ); domain.CreateInstanceAndUnwrap( DOTasm .FullName, /*???*/ ); return /*???*/; } 

最后,作为代码中的这一点,我希望返回一些对象,我可以调用它的属性。 所以调用object obj = new sourceToObj(source).class(); 或某事是可能的。

沿着这条路走下去,这可能确实是错误的道路,这让我有3个未知数。

  • 什么是System.Security.Policy.Evidence assemblySecurity对象。
  • AppDomain.CreateInstanceAndUnwrap()的正确参数是什么
  • 那么我如何将此作为对象返回?

当然这种方法可能是错误的,它基于上面的链接,但没有火鸡。


编辑:经过更多的研究,我想包括一个源文件的例子。

 namespace testNS { public partial class i18Rule { private string i18_Name; private string i18_Value; public void setName(string s) { i18_name = s; } /* Other obvious functions */ }; }; 

我相信我取得了一些进展,并进入了我的问题的第二个条款,如何创建它的实例。

我继续使用AppDomain来包含我的程序集。 我也写了一个写入磁盘的路径,并在一个字节数组中读取它,就像我在Compile c#中发生的这个问题一样。

 /* not the final method, see Philips answer for tryLoadCompiledType which validates this works */ private void sourceToUnitTest(string source, callBack CB) { var pro = new CSharpCodeProvider(); var DOMref = AppDomain.CurrentDomain.GetAssemblies() .Where(obj => !obj.IsDynamic) .Select(obj => obj.Location) .ToArray(); var Cparams = new CompilerParameters( DOMref ); Cparams.OutputAssembly = "SOURCE.DLL"; CompilerResults res = pro.CompileAssemblyFromSource(Cparams, source); Assembly asm = res.CompiledAssembly; Type[] allTypes = res.CompiledAssembly.GetTypes(); foreach (Type t in allTypes) { TryLoadCompiledType(res, t.ToString()); Debug.WriteLine(t.ToString()); } /* I don't return I do something with each type here */ } 

如何将C#源代码编译到内存中,并创建该类的实例?

当我想将源代码作为输入并编译并执行它时,我遇到了类似的问题。 这是我在阅读之后想出的是否可以动态编译和执行C#代码片段? :

 public CompilerResults CompileSource(string sourceCode) { var csc = new CSharpCodeProvider( new Dictionary() { { "CompilerVersion", "v4.0" } }); var referencedAssemblies = AppDomain.CurrentDomain.GetAssemblies() .Where(a => !a.FullName.StartsWith("mscorlib", StringComparison.InvariantCultureIgnoreCase)) .Where(a => !a.IsDynamic) //necessary because a dynamic assembly will throw and exception when calling a.Location .Select(a => a.Location) .ToArray(); var parameters = new CompilerParameters( referencedAssemblies); return csc.CompileAssemblyFromSource(parameters, sourceCode); } 

然后我有一个辅助函数:

  public static object TryLoadCompiledType(this CompilerResults compilerResults, string typeName, params object[] constructorArgs) { if (compilerResults.Errors.HasErrors) { Log.Warn("Can not TryLoadCompiledType because CompilerResults.HasErrors"); return null; } var type = compilerResults.CompiledAssembly.GetType(typeName); if (null == type) { Log.Warn("Compiled Assembly does not contain a type [" + typeName + "]"); return null; } return Activator.CreateInstance(type, constructorArgs); } 

所以把它放在一起

  public void Example(){ dynamic instance = CompileSource("namespace Test{public class DynamicCompile{ /*method*/}}") .TryLoadCompiledType("Test.DynamicCompile"); //can now call methods on 'instance' }