Compile and consume class at runtime
I'm developing a sort of a rules engine, where users define a rule as a set of conditions and actions. Those conditions and 开发者_开发问答actions are then parsed into code to be executed. I am able to generate the code without any issue. I'm stuck at the point of compiling it and then loading the class.
How do I take a string of dynamically generated source code and compile it at runtime?
How can I then execute that code?
I envision being able to have a static list of rules that would be updated as rules are added. Something like:
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);
}
}
Or would I re-compile an assembly and then reload it into my already running app?
I would you recommend to use the Expression Trees instead of dynamically compiling code.
When you compile some source, the resulting assembly is glued into your main application, and cannot be detached anymore. That leads to a growing memory usage, and to a potentially dangerous behaviors. The Expression Trees has been created just for target like yours.
Some rough example (compiling source code, creating instance, calling method with params using Reflection):
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 });
Some links with details:
- http://msdn.microsoft.com/en-us/library/system.codedom.compiler.codedomprovider%28v=VS.100%29.aspx
- http://msdn.microsoft.com/en-us/library/system.codedom.compiler.compilerparameters.aspx
For your case you could make the rules Action<>/delegates which in turn call the compiled methods and put those into the Dictionary<>... so it becomes rather readable when calling them etc.
精彩评论