Template: named formatting

Ahmad Mageed edited this page Apr 19, 2014 · 12 revisions

About

Regextra provides the static Template.Format method to perform named formatting on object properties (including nested properties), Dictionary objects, and dynamic objects. It's also accessible via the FormatTemplate string extension method.

The formatter features:

  • Basic formatting
  • Nested properties formatting
  • Dictionary formatting
  • Escaping of delimiters
  • Standard/Custom/IFormatProvider string formatting
  • Detailed exception messages to pinpoint missing properties

Check out the comparison section later in this document to see how Regextra's Template stacks up to similar libraries!

Basic Formatting

var person = new { Name = "Ahmad" };
var template = "Hi {Name}!";
var result = Template.Format(template, person);
// Hi Ahmad!

Note: dynamic objects are also supported

Extension Method

The FormatTemplate extension method extends string objects.

var person = new { Name = "Ahmad" };
var template = "Hi {Name}!";
var result = template.FormatTemplate(person);
// Hi Ahmad!

Nested Properties Formatting

var item = new
{
    Name = "Ahmad",
    Ide = new
    {
        Name = "Visual Studio",
        Version = 2013
    }
};

var template = "{Name}'s favorite IDE is: {Ide.Name} v{Ide.Version}!";
var result = Template.Format(template, item);
// Ahmad's favorite IDE is: Visual Studio v2013!

Dictionary Formatting

var item = new Dictionary<string, object>()
{
    { "Name", "Ahmad" },
    { "Item", true }
};

var template = "Hello {Name}! The item is {Item}.";
var result = Template.Format(template, item);
// Hello Ahmad! The item is True.

Escaping Delimiters

The { and } delimiters can be escaped by doubling them up, similar to the .NET String.Format approach.

var person = new { Name = "Ahmad" };
var template = "{{Name}} is: {Name}";
var result = Template.Format(template, person);
// {Name} is: Ahmad

Standard/Custom/IFormatProvider Formatting

The same .NET formatting types that you're familiar with can be used with Regextra's Template.

To supply a standard or custom format, append a colon and the desired format inside the delimited property. In other words, use the {PropertyName:format} syntax.

Examples

  • "{Date:t}".FormatTemplate(new { Date = DateTime.Now }) returns 8:45 PM
  • "{Date:M/d/yyyy}".FormatTemplate(new { Date = DateTime.Now }) returns 3/4/2014
  • "{Number:C}".FormatTemplate(new { Number = 1500 }) returns $1,500.00
  • "{Item:N}".FormatTemplate(new { Item = Guid.NewGuid() }) returns a Guid with dashes removed

An overload also exists to supply an IFormatProvider:

Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo("en-GB");
var result = "This item costs {Price:C1}".FormatTemplate(item, NumberFormatInfo.CurrentInfo);
// This item costs £1,234.6

Note

An invalid format will cause a FormatException to be thrown, since this is implemented by using the String.Format method.

Useful Exception Messages

When an object is missing a property used in the template, a MissingFieldException will be thrown and will contain a helpful message to clarify the missing property.

Person Class Example

public class Person
{
    public string Name { get; set; }
}

var person = new Person { Name = "Ahmad" };
var result = "Hi {XYZ}!".FormatTemplate(person);
// Field 'Person.XYZ' not found.

Anonymous Object Example

var person = new { Name = "Ahmad" };
var result = "Hi {XYZ}!".FormatTemplate(person);
// Field '<>f__AnonymousType0`1.XYZ' not found.

Comparison and Performance

Named formatting was a cool idea I wanted to tackle. However, it turns out other people have had similar ideas. Regextra's Template stacks up great. This section exists to compare Regextra and show that it's in good company.

I set out to compare the same libraries that SmartFormat.NET compares itself to. The Benchmarks project shows the benchmark setup. Due to the lack of OSS licenses for those libraries, I've opted not to commit them with the project's code.

Note: if I'm mistaken about the features of any library, or its availability as an OSS library, please let me know.

Comparison

Formatter Non-Nested Properties Nested Properties Dynamic Objects IDictionary Objects Pluralisation List Formatting
Regextra Template Y Y Y Y - -
SmartFormat.NET Y Y Y Y Y Y
Henri Y Y - - - -
Haack Y Y - - - -
James Y - - - - -
Hanselman Y - - - - -
Oskar Y - - Y - -

Performance

The following benchmark results are ordered by best performance. Most of the top performers are fairly close to each other.

1000 Iterations Sample Template

Note: Regextra, SmartFormat, and Haack formatters tied for 2nd place @ 14 ms.

  1. Henri: 9 ms -- 0.009 ms/iteration
  2. Regextra Template w/FastMember: 14 ms -- 0.014 ms/iteration
  3. SmartFormat.NET: 14 ms -- 0.014 ms/iteration
  4. Haack: 14 ms -- 0.014 ms/iteration
  5. SmartFormat.NET (Cached): 15 ms -- 0.015 ms/iteration
  6. Regextra Template w/Reflection: 16 ms -- 0.016 ms/iteration
  7. James: 21 ms -- 0.021 ms/iteration
  8. Hanselman: 35 ms -- 0.035 ms/iteration
  9. Oskar: 67 ms -- 0.067 ms/iteration

1000 Iterations Nested Sample Template

  1. Henri: 17 ms -- 0.017 ms/iteration
  2. Haack: 23 ms -- 0.023 ms/iteration
  3. Regextra Template w/FastMember: 25 ms -- 0.025 ms/iteration
  4. SmartFormat.NET: 26 ms -- 0.026 ms/iteration
  5. SmartFormat.NET (Cached): 27 ms -- 0.027 ms/iteration
  6. Regextra Template w/Reflection: 29 ms -- 0.029 ms/iteration

1000 Iterations Dictionary Template

  1. Regextra Template: 8 ms -- 0.008 ms/iteration
  2. SmartFormat.NET: 11 ms -- 0.011 ms/iteration
  3. Oskar: 31 ms -- 0.031 ms/iteration

1000 Iterations ExpandoObject Template

  1. Regextra Template: 12 ms -- 0.012 ms/iteration
  2. SmartFormat.NET: 15 ms -- 0.015 ms/iteration

1000 Iterations Dynamic Person Template

  1. Regextra Template w/FastMember: 23 ms -- 0.023 ms/iteration
  2. SmartFormat.NET: 30 ms -- 0.03 ms/iteration

Related links: