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