C# CodeDom Inline Compiling

I was a bit bored just now and since the WYSIWYG editor of WordPress 2.9.2 doesn’t work as optimal as I had hoped, I decided to write my own program that translates forum posts with BB code into HTML.

Of course I could have put all these replace functions into the code but then I would have to adapt the code every time I find a new tag.

So I thought this might be a good time to toy with the Inline Compiler of C#. And if done right, it is relatively easy.

Here’s my first Inline Compiling Code Snippet (it doesn’t contain any error handling and some such, but you get the idea how it works):

using System;
using System.CodeDom.Compiler;
using Microsoft.CSharp;
using System.Xml.Serialization;
using System.IO;
using System.Text;

namespace DoenaSoft.InlineCompiling
{
  public static class Program
  {
    static void Main()
    {   
      ParamList pl;

      //to create a sample XML file:
      pl = new ParamList();
      pl.Params = new Param[1];
      pl.Params[0] = new Param();
      pl.Params[0].Name = "Kursiver Text";
      pl.Params[0].Regex 
        = "\\\\[i\\\\](?'Text'.+?)\\\\[/i\\\\]";
      pl.Params[0].RegexOptions = "RegexOptions.Compiled"
        + "| RegexOptions.Singleline "
        + "| RegexOptions.IgnoreCase";
      pl.Params[0].Code = "\"\""
        + " + match.Groups[\"Text\"].Value + \"\"";
      using(FileStream fs = new FileStream("params.xml"
        , FileMode.Create, FileAccess.Write
        , FileShare.None))
      {
        XmlSerializer xmls 
          = new XmlSerializer(typeof(ParamList));

        xmls.Serialize(fs, pl);
      }
      //end creating sample XML file

      using(FileStream fs = new FileStream("params.xml"
        , FileMode.Open, FileAccess.Read
        , FileShare.Read))
      {
        XmlSerializer xmls 
          = new XmlSerializer(typeof(ParamList));

        pl = (ParamList)(xmls.Deserialize(fs));
      }

      String text = "[i]some text[/i]";

      foreach(Param param in pl.Params)
      {
        CSharpCodeProvider scp;
        CompilerParameters cp;
        CompilerResults cr;
        Object replacer;
        StringBuilder sb;

        sb =  new StringBuilder();
        sb.AppendLine("using System;");
        sb.AppendLine("using System.Text."
          + "RegularExpressions;");
        sb.AppendLine();
        sb.AppendLine("public class RegexReplacer");
        sb.AppendLine("{");
        sb.AppendLine("  private static readonly Regex "
          + "s_Regex = new Regex(\"" + param.Regex 
          + "\", " + param.RegexOptions + ");");
        sb.AppendLine();
        sb.AppendLine("  private String Replace(Match "
          + "match)");
        sb.AppendLine("  {");
        sb.AppendLine("    return (" + param.Code 
          + ");");
        sb.AppendLine("  }");
        sb.AppendLine();
        sb.AppendLine("  public String Replace(String "
          + "text)");
        sb.AppendLine("  {");
        sb.AppendLine("    return (s_Regex.Replace(text"
          + ", new MatchEvaluator(this.Replace)));");
        sb.AppendLine("  }");
        sb.AppendLine("}");

        scp = new CSharpCodeProvider();
        cp = new CompilerParameters();
        cp.ReferencedAssemblies.Add("System.dll");
        cr = scp.CompileAssemblyFromSource(cp
          , sb.ToString());
        replacer = cr.CompiledAssembly
          .CreateInstance("RegexReplacer");
        text = replacer.GetType().GetMethod("Replace")
          .Invoke(replacer, new Object[] { text })
          .ToString();
      }
    }
  }

  [Serializable()]
  public class ParamList
  {
    [XmlArrayItem("Param")]
    public Param[] Params;
  }

  [Serializable()]
  public class Param
  {
    public String Name;
    public String Regex;
    public String RegexOptions;
    public String Code;
  }
}