在运行时编译和使用类

时间:2011-08-20 00:20:51

标签: c# code-generation metaprogramming

我正在开发一种规则引擎,用户将规则定义为一组条件和操作。然后将这些条件和操作解析为要执行的代码。我能够毫无问题地生成代码。我一直处于编译它然后加载课程的时候。

如何获取一串动态生成的源代码并在运行时编译它?

如何执行该代码?

我设想能够拥有一个静态的规则列表,这些规则将在添加规则时更新。类似的东西:

static Dictionary<string, Rule> Rules { get; set; }
static void RefreshRules ()
{
    var newRules = DataLayer.GetRules().Where(r => !this.Rules.ContainsKey(r.Name));
    foreach (var rule in newRules)
    {
        this.Rules[rule.Name] = CompileRule(rule.Code);
    }
}

或者我会重新编译程序集然后将其重新加载到我已经运行的应用程序中吗?

2 个答案:

答案 0 :(得分:5)

我建议您使用Expression Trees而不是动态编译代码。

编译某些源代码时,生成的程序集会粘贴到主应用程序中,并且不能再分离。这会导致内存使用量增加,并导致潜在的危险行为。表达树已经为像你这样的目标创建了。

答案 1 :(得分:3)

一些粗略的例子(编译源代码,创建实例,使用反射使用参数调用方法):

CodeDomProvider P = System.CodeDom.Compiler.CodeDomProvider.CreateProvider("C#");
CompilerParameters O = new CompilerParameters();
O.GenerateInMemory = true;
O.ReferencedAssemblies.Add(@"System.dll");
//O.ReferencedAssemblies.Add(@"System.Net.dll");

O.IncludeDebugInformation = false;

CompilerResults R = P.CompileAssemblyFromSource(O, new string[] { "using System; using System.Reflection; namespace ABC.TestXXX {     // your source code goes here }" });

Assembly _B_ = R.CompiledAssembly;
// create an instance
object YY = _B_.CreateInstance("ABC.TestXXX.MyClass");
// call method returning bool and taking one string and one object
YR = (bool)_B_.GetType("ABC.TestXXX.MyClass").GetMethod("TestB").Invoke(YY, new object[] { "Hallo", SomeObject });

一些细节链接:

对于您的情况,您可以制定规则Action&lt;&gt; / delegates,然后调用已编译的方法并将它们放入Dictionary&lt;&gt; ...中,以便在调用它们时变得相当可读。