Some of my Code Concepts articles and Hands-on programming posts are building towards something bigger: a small compiler and parser of sorts — a simple Reverse Polish Notation calculator. In this column, I integrate a few of the pieces together.

I'll show how to create a generic class that can be retrieved by name and a class that inherits from the generic class and pre-loads itself with functions stored in an external configuration at compile time. (In case you missed my articles about T4 templates and lambda expressions, I suggest reviewing them before reading this article if you are not familiar with those ideas.)

Example
Our generic class is pretty easy to write. Internally, it will use a Dictionary object to hold the functions and support a few simple methods (Add(), Remove(), Get(), and an indexer). Here's the code:

public class FuncLibrary<T1, TResult>

{

private Dictionary<string, Func<T1, TResult>> _functions;

public Func<T1, TResult> this[string name]

{

get

{
return _functions[name];

}

set

{

_functions[name] = value;

}

}

public void Add(string name, Func<T1, TResult> function)

{

_functions.Add(name, function);

}

public bool Remove(string name)

{

return _functions.Remove(name);

}

public Func<T1, TResult> Get(string name)

{

return this[name];

}

public FuncLibrary()

{

_functions = new Dictionary<string, Func<T1, TResult>>();

}

}

You might be wondering why the first type is T1 and not T; you may also notice that the functions it stores can only accept one parameter. I call the type T1 because it is an exercise for you to copy/paste the code into a new class that accepts two parameters and make the needed changes. For my purposes, I made five versions, accepting from 0 to 4 parameters.

Now that we have a useful, generic class, it is time to look at our specific needs. For our RPN calculator, I decided that it will work in a fairly Lisp-like fashion, operating entirely on lists. As a result, all of the function inputs and outputs will be List<float> objects. What we need to do now is make a new class that subclasses FuncLibrary<T1, TResult>:

public class Functions : FuncLibrary<List<float>, List<float>> {
}

So far, so good. But, how will we pre-load this library with functions at compile time from an external source? This is where the T4 templates come into play.

First, we will make a simple XML file that can hold our functionality. Here is a truncated version of that XML file:

<?xml version="1.0″ encoding="utf-8″ ?>
<functions>

<function name="add">

<![CDATA[

var result = input[0];

for (int counter = 1; counter <= input.Count - 1; counter++) {

result += input[counter];

}

return new List<float>{ result };
]]>
</function>
</functions>

If you look at the code within the CDATA block, you may wonder where the variable input came from — that is the name our system will give to the input to each function when it creates the lambda expressions. Remember, the input is of type List<float>; the T4 template will parse this XML and create lambda expressions with this data and add it to our new Functions class in the constructor. Let's get started on the template.

It should start with a number of directives to declare the language as C# 3.5 (if you just declare it as C#, we won't have access to things like var, which would be a problem for the LINQ), reference the needed assemblies and load the namespaces the T4 code will need:

<#@ template language="C#v3.5″ #>
<#@ assembly name = "System.Core" #>
<#@ assembly name = "System.Xml" #>
<#@ assembly name = "System.Xml.Linq" #>
<#@ import namespace = "System" #>
<#@ import namespace = "System.Linq" #>
<#@ import namespace = "System.Xml" #>
<#@ import namespace = "System.Xml.Linq" #>
<#@ import namespace = "System.IO" #>

Next, we put in the body of our class, including any using statements that the defined functions might use:

public class Functions : FuncLibrary<List<float>, List<float>> {
public Functions() {
}
}

Now we need to fill in the constructor, but put T4 code in it that does the heavy lifting:

<#
var functionListLocation = @"C:\Users\jjames\Documents\Source Control Working Copy\TitaniumCrowbarUtilities\ExtendableRPNCalculator\FunctionList.xml";
var rawXml = File.ReadAllText(functionListLocation);
var functionList = XDocument.Parse(rawXml);

var functions = from function in functionList.Root.Elements() select function;

foreach (var item in functions)
{
var funcName = item.Attribute("name").Value;
var lambdaName = "lambda_" + funcName;

this.Write("Func<List<float>, List<float>> " + lambdaName + " = input => {\n");
this.Write(item.Value);
this.Write("};\n");
this.Write("Add(\"" + funcName + "\", " + lambdaName + ");\n");
}
#>

The first line of code is the hard-coded path to the XML file; I haven't found a good way around this yet. Next, we read in the XML file and load it into an XDocument object. We iterate through each of the function elements in the XML document, and for each one, we extract the name attribute and store it in the funcName variable. We then create a variable name for the generated code to hold the new lambda expression in, making sure that it will be unique by prefixing it with lambda_ (ugly, I know). Then we write to the output stream, first defining the lambda expressions by outputting a variable declaration and creating a lambda, then writing the contents of the function element, and finally, closing up the lambda definition and ending the variable declaration. The last thing we do is call the class's Add() method with the new function's name and the lambda expression. The T4 template gets run any time we tell Visual Studio to "Save", even if the contents have not changed. Go ahead and do so, and take a look at the output (for me, it gets put into Functions1.cs since I named my template file Functions.cs):

using System;
using System.Collections.Generic;
using FunctionLibrary;

public class Functions : FuncLibrary<List<float>, List<float>> {
public Functions() {
Func<List<float>, List<float>> lambda_add = input => {

var result = input[0];
for (int counter = 1; counter <= input.Count - 1; counter++) {
result += input[counter];

}

return new List<float>{ result };
};
Add("add", lambda_add);
}
}

Pretty neat, huh? If it doesn't seem particularly useful at the moment, consider the possibilities. The code could be stored in a database, allowing you to maintain a system where customer-specific modifications can be loaded at compile time without needing to touch to core code. You could also create a Domain Specific Language (DSL) for the code in the configuration, allowing business users or other specialists to create the functionality that gets turned into actual .NET code when you compile everything together. The possibilities are limitless, and soon we will have a parser to start making calls to our function library.

This article was originally published on TechRepublic.

Cast your .NET This was published in Cast your .NET, check every Thursday for more stories

Related links

Leave a comment

You must read and type the 6 chars within 0..9 and A..F

* indicates mandatory fields.

Log in


Sign up | Forgot your password?

  • Staff Microsoft shows off IE9 preview

    This week, highlights from Microsoft's MIX10 conference and more in the Roundup. Read more »

    -- posted by Staff

  • Chris Duckett IE9's H.264 vote killed Ogg

    In a split decision by the judges, the winner of the W3C/WHATWG video codec consensus is H.264, taking home the future of video playback on the internet while loser Ogg goes home with nothing but thoughts of what might have been. Read more »

    -- posted by Chris Duckett

  • Staff Google launches Apps Marketplace

    Google launches and app store, while Mozilla plans to re-write its open-source license. More of this week's news in the Roundup. Read more »

    -- posted by Staff

What's on?

  • Optus Deal

    Broadband + home phone + PlayStation®3 in a single package price!