C# CompilerResults GenerateInMemory? [英] 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屋!