2

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?

gilly3
  • 87,962
  • 25
  • 144
  • 176
  • Start here: http://msdn.microsoft.com/en-us/library/650ax5cx.aspx; I have used the CodeDom in the past, but have no code samples handy for a proper answer. – Chris Baxter Aug 20 '11 at 00:30
  • Check out http://stackoverflow.com/questions/5766373/how-does-linqpad-compile-code – Aaron Anodide Aug 20 '11 at 01:26
  • Is there a reason you don't want to use a rules engine, like Drools? –  Aug 20 '11 at 01:42
  • Have you considered using `System.Reflection.Emit` directly? Sometimes it is easier than the Expression Trees. – SK-logic Aug 21 '11 at 11:17

2 Answers2

5

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.

Dirk Vollmar
  • 172,527
  • 53
  • 255
  • 316
Mario Vernari
  • 6,649
  • 1
  • 32
  • 44
3

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:

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.

Yahia
  • 69,653
  • 9
  • 115
  • 144