PrecompiledRegex.Fody

Fody add-in that compiles regular expressions at build-time

Stars
7

PrecompiledRegex.Fody

PrecompiledRegex.Fody automatically compiles constant regular expressions in your code as part of the build process, both improving performance and providing compile-time validation for your regular expressions.

To set it up, all you need to do is install the NuGet package .

This is an add-in for Fody

Introduction to Fody

Why Pre-compile?

.NET regular expressions can be compiled to IL code for maximum performance. While this performance gain is valuable, it comes at a non-trivial cold startup cost. One way to get the best of both worlds is to pre-compile your regular expressions to an assembly. However, this is tedious to do since it happens outside of the normal build process. It also makes your code less readable and more difficult to change. PrecompiledRegex.Fody provides the benefits of precompilation for normal-looking regex code and as part of the standard build process: after the project is built, the tool scans the output assembly for usages of regular expressions and where possible pre-compiles them, merges the generated code into the assembly, and replaces the references with references to the pre-compiled state machines.

What You Write

public void SomeMethod()
{
	var regex = new Regex("f.*o", RegexOptions.IgnoreCase);

	if (regex.IsMatch("foo")) { ... }
	else if (Regex.IsMatch("bar", "b.*r")) { ... }
}

What Gets Compiled

public void SomeMethod()
{
	var regex = RegularExpressions.PrecompiledRegex001();

	if (regex.IsMatch("foo")) { ... }
	else if (RegularExpressions.PrecompiledRegex002().IsMatch("bar")) { ... }
}

// generated class which caches pre-compiled regex instances for reuse
internal class RegularExpressions
{
	private static Regex cachedPrecompiledRegex001, cachedPrecompiledRegex002;

	public static Regex PrecompiledRegex001()
	{
		// PrecompiledRegex001 is a type generated by Regex.CompileToAssembly()
		return cachedPrecompiledRegex001 ?? (cachedPrecompiledRegex001 = new PrecompiledRegex001());
	}

	public static Regex PrecompiledRegex002()
	{
		// PrecompiledRegex002 is a type generated by Regex.CompileToAssembly()
		return cachedPrecompiledRegex002 ?? (cachedPrecompiledRegex002 = new PrecompiledRegex002());
	}
}

Other Benefits

  • Compile-time validation: because pre-compiled regular expressions are evaluated at build time, PrecompiledRegex.Fody can and does report a build error if a pattern does not represent a valid regular expression
  • Object re-use: For efficiency, pre-compiled regex instances are cached and re-used for the lifetime of the application. However, this is done lazily such that no work happens before a Regex object is actually required. For regexes that have a match timeout specified, the last instance will be re-used if the timeouts match. In most real cases (where the timeout for a single pattern does not vary), this should result in 100% re-use.

Functionality and Limitations

Supported Methods

All Regex constructors and both instance and static matching methods (e. g. Matches, Split, Replace) are supported. This includes overloads which take in a match timeout.

In order to be a candidate for precompilation, the pattern and options arguments must be compile-time constants:

// valid
Foo // where Foo is a const field or variable
"a string literal"
RegexOptions.IgnoreCase
RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture

// invalid
Foo // where Foo is a property or non-const field or variable
GetPattern() // the result of a function call
condition ? RegexOptions.None : RegexOptions.IgnoreCase // the result of branching

You can inspect the build output for detailed information about which expressions PrecompiledRegex.Fody determines can be pre-compiled.

Configuration

Fody supports configuration of add-ins via the FodyWeavers.xml file. The PrecompiledRegex element supports the following configuration options:

Attribute Name Values Default
Include All attempts to pre-compile all expressions. Compiled attempts to precompile only regexes with RegexOptions.Compiled specified. All
NoOpBehavior Warn emits a build warning if no pre-compilable regexes were found. This is useful to ensure that your regexes are benefiting from the functionality. Silent disables this warning Warn