C#CompilerResults GenerateInMemory?

Aag*_*eif 7 c# .net-assembly

我一直在关注这个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 /*???*/;
}
Run Code Online (Sandbox Code Playgroud)

最后,作为代码中的这一点,我希望返回一些对象,我可以调用它的属性.所以打电话 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 */
  };
};
Run Code Online (Sandbox Code Playgroud)

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

我继续使用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 */
}
Run Code Online (Sandbox Code Playgroud)

Phi*_*tle 6

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

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

public CompilerResults CompileSource(string sourceCode)
{
        var csc = new CSharpCodeProvider(
            new Dictionary<string, string>() { { "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);
 }
Run Code Online (Sandbox Code Playgroud)

然后我有一个辅助函数:

 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);
    }
Run Code Online (Sandbox Code Playgroud)

所以把它放在一起

   public void Example(){
       dynamic instance = 
            CompileSource("namespace Test{public class DynamicCompile{ /*method*/}}")
            .TryLoadCompiledType("Test.DynamicCompile");

        //can now call methods on 'instance'
   }
Run Code Online (Sandbox Code Playgroud)