我一直在关注这个StackOverflow问题.它是我能找到的最接近的东西,但并不完全.
让我在我的问题之前解释一下我的最终目标是什么,我正在制作一个支持web的编译器平台,因此,我想在内存中做所有事情(不做任何文件),所以我希望能够编译代码,然后能够引用我刚编译的类中的对象进行任意测试.我知道它听起来有多安全,所以欢迎提供安全方面的意见.
我的问题是如何将C#源代码编译到内存中,并创建该类的实例?
目前我正处于一个步骤,我可以生成有效的.dll并导入并在VisualStudio中手动使用它.
接下来的两个步骤是:
为了完全在记忆中尝试这个,我试过这个.(来源说明)
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)
如何将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)