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");