C# CodeDom Inline Compiling

Author:

Mir war grad etwas langweilig, und da der WYSIWYG-Editor von WordPress 2.9.2 nicht ganz so optimal funktioniert, wie ich mir das wünschen würde, habe ich beschlossen, die Umsetzung von Forenbeiträgen mit BB-Code auf HTML lieber selbst in ein Programm zu gießen.

Natürlich könnte ich die ganzen Ersetzungsfunktionen alle in Code gießen, aber dann müsste ich ja jedesmal den Code anpassen, wenn ich mal ein neues Tag finde.

Also habe ich gedacht, es wäre mal an der Zeit, etwas mit dem Inline-Compiler von C# rumzuspielen. Und wenn man es richtig macht, ist es sogar relativ einfach.

Hier mal mein erstes Inline Compiling Code Snippet (da ist noch keine Fehlerbehandlung und nichts drin, aber man bekommt eine Idee, wie es funktioniert):

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;
  }
}