C#的CompilerResults GenerateInMemory? [英] C# CompilerResults GenerateInMemory?

查看:96
本文介绍了C#的CompilerResults GenerateInMemory?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I've been following this StackOverflow question. Its the closest thing I can find, but not quite.

让我解释一下我的最终目标是什么,我正在制作一个支持Web的编译器平台,因此,我想在内存中做所有事情( 不创建文件),因此我希望能够编译代码,然后能够引用我刚刚编译的类中用于任意测试的对象。我知道这听起来很不安全,因此欢迎您输入有关安全性的信息。

Let me explain what my end goal is before my question, I'm making a compiler platform that's web enabled, because of that, I want to do everything in memory (make no files), so I want to be able to compile code, and then be able to reference the objects in the class I just compiled for arbitrary testing. I know how it unsafe it sounds, so input in regard to security is welcome.

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

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

Currently I'm at a step where I can generate valid .dll's and import and use it inside VisualStudio by hand.

接下来的2个步骤是:


  • 自动加载程序集(这是我在这里询问的内容


    • 这意味着我不再需要给出dll的路径,并获得随附的地址班级成员手工


    • 此意思是说我可以在没有成员先验知识的情况下创建类的接口,有点像foreach循环如何在键值对上工作。

    要完全在内存中尝试此操作,我已经尝试过了。 (然后说明来源)

    To attempt this entirely in memory I've tried this. (source then explanation)

    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(); 还是有可能的。

    Finally, as this point in the code I'd hope to return some object I can call a property of. So calling object obj = new sourceToObj(source).class(); or something would be possible.

    走这条路,这的确是错误的路,给我留下了3个未知数。

    Going down this path, which may indeed be the wrong path leaves me with 3 unknowns.


    • 什么是 System.Security.Policy.Evidence assemblySecurity 对象

    • AppDomain.CreateInstanceAndUnwrap()
    • 的正确参数是什么>
    • 然后我如何将其作为对象返回?

    • What is a System.Security.Policy.Evidence assemblySecurity object.
    • What is the proper parameter for AppDomain.CreateInstanceAndUnwrap()
    • How then do i return this as an object?

    当然此方法可能是错误的,它基于上面的链接很近,但没有土耳其。

    Of course this method could be wrong, it's based off the link above which is close, but no turkey.

    编辑:经过更多研究,我想提供一个源文件示例。

    After more research I wanted to include an example of a source file.

    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 */
      };
    };
    






    我相信我取得了一些进步,进入我的问题的第二个子句,即如何创建它的实例。


    I believe I made a little bit of progress and went onto the second clause of my question, how to create an instance of it.

    我继续使用AppDomain来包含我的程序集。我也按照写在磁盘上并将其读取为int字节数组的方法进行了编码,正如我在即时编译c#

    I went ahead and used an AppDomain to contain my assembly. I also went the route of writing to disk and reading it int a byte array as done in this question i happened upon Compile c# on the fly.

    /* 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#源代码编译到内存中,并创建该类的实例?

    How do I compile C# source to memory, and create an instance of that class?

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

    I faced a similar issue when I wanted to take source code as input and compile and execute it. This is what I came up with after reading Is it possible to dynamically compile and execute C# code fragments?:

    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);
     }
    

    然后我有一个辅助函数:

    Then I have a helper function:

     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'
       }
    

    这篇关于C#的CompilerResults GenerateInMemory?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆