On numerous occations I’ve had to do some runtime creation of C# code. In the early days, I was tempted to directly write each source line to a file.
But quickly discovering, that I needed a solution where I could use template based generation of texts (source code). Where I can easily change certain parts of the text, but maintain the overall skeleton.
For this I’ve been using the following class quite often:
using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text.RegularExpressions; namespace TriGemini.Templating { /// <summary> /// TextTemplate Class /// Written By Henrik Brinch (TriGemini) /// www.trigemini.dk / www.henrikbrinch.dk /// Check out www.linkedin.com/in/trigemini /// /// License terms: Feel free to use the code in your own projects, however if distributing /// the source code, you must preserve this heading. /// /// Please do not post this code on other sites, but link to this blog-post instead. /// If you really find it usefull and use it in commercial application, I'd like to hear about /// it - and you're very welcome to mention me your application credits :-) /// </summary> public class TextTemplate { #region Private Fields private static readonly Regex _regex = new Regex(@"###(?<TAG>\w+)###", RegexOptions.Compiled); private readonly Dictionary<string, string> _tags = new Dictionary<string, string>(); #endregion #region Public Properties public string TemplateContent { get; private set; } public string this[string tagName] { get { string result; _tags.TryGetValue(tagName, out result); return result; } set { if (!_tags.ContainsKey(tagName)) { _tags.Add(tagName, value); } else { _tags[tagName] = value; } } } #endregion #region Public Methods public static TextTemplate FromEmbeddedResource(string name) { TextTemplate result; var asm = Assembly.GetExecutingAssembly(); using (var stream = asm.GetManifestResourceStream(name)) { result = FromStream(stream); } return result; } public static TextTemplate FromStream(Stream stream) { var result = new TextTemplate(); using (var reader = new StreamReader(stream)) { result.TemplateContent = reader.ReadToEnd(); } return result; } public void ToStream(Stream stream) { using (var writer = new StreamWriter(stream)) { writer.Write(ToString()); } } public void ToStream(string filename) { using (var writer = new StreamWriter(filename)) { writer.Write(ToString()); } } public override string ToString() { return _regex.Replace(TemplateContent, match => { var tagName = match.Groups["TAG"].Value; return this[tagName] ?? String.Empty; }); } #endregion } }
Example usage
I’ve chosen the characters “###” as enclosing mark for a tag (defined by the regular expression in the TextTemplate class). So e.g. ###NAME### acts as a position within the template, that needs to be replaced with the given tag content. Take the very simple text file:
Hello ###NAME### how are you today?
I can choose to place this template e.g. as an embedded text resource in my project or enclose it as file. To use it, I can do the following code:
var temp = TextTemplate.FromEmbeddedResource("MyNamespace.TestFile.txt"); temp["NAME"] = "Henrik"; temp.ToStream(@"c:\temp\output.txt");