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

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

问题描述

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

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

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

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.

我接下来的两个步骤是:

My next 2 steps are:

  • 自动加载程序集(这就是我在这里问的)
    • 这意味着我不再需要提供 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 来包含我的程序集.我还采用了写入磁盘并将其读取为字节数组的方法,就像在这个问题中所做的那样,我遇到了 即时编译 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天全站免登陆