Wednesday, December 10, 2008

Tuples...

Tuples (which I have always pronounced 'tuh-pul' and others pronounce 'too-pull') are interesting data structures in that they combine two or more pieces of otherwise unrelated data of any types. They are most common (and supported) in functional languages, where they are considered first-class language constructs. For example, to create a Tuple in F#, you simply surround the elements you want to tuplize in a set of parenthesis: [ let x = (1, "one") ] - x in this case will have the type [ int * string ].

You may not realize it yet, but tuples have been around in .NET since 2.0 - the KeyValuePair generic class is, essentially, an immutable tuple of any two values. Using it as such, though, is unwieldy in my opinion - its purpose was to facilitate enumerating through dictionaries, and while it works fine in this context, KeyValuePair is ill-suited to more generic purposes.

During my experimentation with F# and other functional languages, I've come to see the Tuple type as a very valuable data structure that I miss very much when working on "real-world" code (real-world in this context meaning what I do for a living). .NET has no Tuple type, and while I'm aware that .NET 4 will have this type, that doesn't help me now. I could use the F# tuple types in my C# code, yes - but I'd have to distribute the F# binaries with my software, and I don't want to do that if I'm not using F#. My only other options are to use someone else's library, or roll my own. I've opted for the latter.

I've implemented four immutable tuple struct types, which hold between two and 5 values. Additionally, I implemented several helper methods and extension methods that make working with the Tuples a little easier in C#. Here's the code for the two-value Tuple struct:

    1 public struct Tuple<T1, T2> {

    2     private readonly T1 _value1; public T1 Value1 { get { return _value1; } }

    3     private readonly T2 _value2; public T2 Value2 { get { return _value2; } }

    4     public Tuple(T1 value1, T2 value2) { _value1 = value1; _value2 = value2; }

    5 

    6     public override bool Equals(object obj) {

    7         if (!(obj is Tuple<T1, T2>)) return false;

    8         if (obj == null) return false;

    9 

   10         Tuple<T1, T2> t = (Tuple<T1, T2>)obj;

   11         return (Value1.Equals(t.Value1) && Value2.Equals(t.Value2));

   12     }

   13 

   14     public override int GetHashCode() {

   15         return Value1.GetHashCode() ^ Value2.GetHashCode();

   16     }

   17 

   18     public KeyValuePair<T1, T2> AsKeyValuePair() {

   19         return new KeyValuePair<T1, T2>(Value1, Value2);

   20     }

   21 }

   22 ...

   23 

   24 public static class Tuples {

   25     public static Tuple<T1, T2> Tuple<T1, T2>(T1 value1, T2 value2) {

   26         return new Tuple<T1, T2>(value1, value2);

   27     }

   28     ...

   29 

   30     public static Tuple<T1, T2> Default<T1, T2>() {

   31         return new Tuple<T1, T2>(default(T1), default(T2));

   32     }

   33     ...

   34 

   35     public static IEnumerable<Tuple<T1, T2>> Zip<T1, T2>(IEnumerable<T1> first, IEnumerable<T2> second) {

   36         var enum1 = first.GetEnumerator();

   37         var enum2 = second.GetEnumerator();

   38 

   39         while (enum1.MoveNext() && enum2.MoveNext()) {

   40             yield return Tuple(enum1.Current, enum2.Current);

   41         }

   42     }

   43     ...

   44 }

   45 

   46 public static class TupleExtensions {

   47     public static Tuple<IEnumerable<T1>, IEnumerable<T2>> Unzip<T1, T2>(this IEnumerable<Tuple<T1, T2>> ienum) {

   48         var first = new List<T1>();

   49         var second = new List<T2>();

   50 

   51         foreach (var t in ienum) {

   52             first.Add(t.Value1);

   53             second.Add(t.Value2);

   54         }

   55 

   56         return Tuples.Tuple(first.AsEnumerable(), second.AsEnumerable());

   57     }

   58     ...

   59 

   60     public static Tuple<T1, T2> AsTuple<T1, T2>(this KeyValuePair<T1, T2> kvp) {

   61         return Tuples.Tuple(kvp.Key, kvp.Value);

   62     }

   63 }


The '...'s denote where the pattern is extended to cover all the tuple value counts from 2 to 5.

Only a little explanation is really needed here - the Tuple structs are read-only, so once they're initialized they can't be reset. In my experience this isn't a problem - I've never really *needed* that functionality where I can't just create a new Tuple. The static 'Tuples' class makes it easier to initialize a Tuple - using this, I can create a Tuple from existing data without having to add the type parameters. The compiler figures it out from the existing type data. Can't do this with constructors, sadly. The 'AsKeyValuePair' and 'AsTuple' methods (which only work with the 2-tuple struct) are pretty self explanatory.

The Zip method takes two or more IEnumerables and 'zips' them together into a single IEnumerable of Tuples. The Unzip method sort performs the reverse, although since you can only return one value from a method I package the unzipped Enumerables in a single Tuple.

If you'd like to use this in your own projects, I've uploaded my Tuples file to PasteBin - you can get to it from here. No attribution needed - though it would be nice if you'd drop a line here to let me know it's been useful to you. =)

Tuesday, December 9, 2008

Workflow Foundation 4, plus Macrocrafter stuff.

Um... Wow. I'm really looking forward to WF4. I've been interested in Workflow since Whidbey, and I'm very glad to see it's all getting much more streamlined and easier to work with. I watched the PDC talk that Matt Winkler gave which included a number of demos - you can watch it here and be awed just like me!

I particularly liked how much easier it seems to be to rehost the workflow designer - this is going to be central to one of my pet projects, which I have yet to talk about here...

Before I go - I promised on my old Macrocrafter programming blog that I would talk about Macrocrafter projects as well as my hobby and work-related projects, so I shall. I have three Macrocrafter-related projects that I'm going to be working on for EQ2. Two of them are directly related, and I probably should just count them as one project - one of them is an EverHarvest rewrite, and the other is integrating a hunting box into EverHarvest.

I've talked about this before, but since Life hit me full-on about half a year back (and hasn't let up until very recently), I've been unable to start this project. The plan is to have EverHarvest and the hunter bot (once called AutoGrind, then AG, then Silver [if you can catch the reference], but no longer) share a codebase, since they're so incredibly similar. Both programs require walking around, both target things, both activate in-game functions when a target is acquired, etc. Integrating the two will give users of both 'sub-programs' the best of both worlds - if you're harvesting, you can defend yourself - and if you're hunting, you can harvest during the interim.

The licensing model for this is something I've talked about before as well. Even though I'm combining the programs, I plan on keeping the licensing separate. EverHarvest will continue to work on its own (with no hunter bot functionality) if you never buy a hunter bot license. Same with the hunter bot. But if you buy a license for both (and there will be some sort of package deal, as well as a grandfathering deal for current EH users), you'll get functionality for both.

My third Macrocrafter project is, well, a cheat program, pure and simple. Speed hack, teleport, safe-fall, etc. It will *not* be safe for use - in fact, it's cheating, so if you use it excessively expect to catch a ban.

Well, that's all for now. Time to get back to work - they're not paying me to blog. =)

Wednesday, November 26, 2008

Recursive Descent and grander ideas

I've spent the past week or so of spare time in between working on shipping projects refining my adventure game idea, and I've come to a decision. I'm not going to make an adventure game; instead, I'm going to reinvent MUDs. I have some experience with MUDs, and while I enjoy the concept greatly (especially allowing users to create the environment), I have never enjoyed the command interface. Too many non-intuitive commands to do things (especially allowing users to create the environment).

Part of my reinvention is to fix what I find to be this most annoying of issues - the lack of a natural-language-esque command system. To that end, I've been studying parsing, compiler-compilers, EBNF rules, all sorts of fun things. My initial path through this landscape took me to compiler-compilers like YACC, ANTLR, etc., but I grew frustrated by my lack of understanding into the problem domain.

So yesterday I decided to take a different route. I figured I'd retrace the steps it takes to create a compiler-compiler; that is, I must first understand compilers. To this end, I wrote a very simple expression parser, using recursive descent over an LL(1) grammar. Here's the grammar:

    1 //assignment:    ID EQU expression EOF

    2 //expression:    term (PLUSMINUS term)*

    3 //term:            factor (MULDIV factor)*

    4 //factor:        MINUS? (NUMBER | ID | LPAREN expression RPAREN)

    5 

    6 //ID:            [a..z A..Z]+

    7 //NUMBER:        [0..9]+

    8 //PLUSMINUS:    '+' | '-'

    9 //MULDIV:        '*' | '/'

   10 //EQU:            '='

   11 //LPAREN:        '('

   12 //RPAREN:        ')'

   13 //EOF:            [EOF]


The purpose is to parse expressions such as 'vara = 1 + 2 / (3 * varb)' and then evaluate the resulting tree. I'm not really sure if what I'm building is an Abstract Syntax Tree or not, but it suits my purposes. Anyway this is just my first attempt.

I wrote a scanner, which takes an input stream and returns tokens from it sequentially (a token being one valid element in the grammar), a parser which uses the scanner and returns a tree by consuming the tokens, and an evaluator which performs the work of turning the tree structure into run-time instructions. I added some state to the evaluator, such that it will store the expressions as assigned to variables so that other expressions can make use of them.

One neat feature I added was persistent expression evaluation - instead of storing just the result value of an expression with its label, I store the expression itself. This means that changing the value of one variable will change the value of all other variables that depend on the changed variable, and so on. Say I've got the following:

a = 1
b = a + 1
c = b + 1
d = a + b + c

d's final value here is '6' - but when I change a = 5, b becomes 6, c becomes 7, and d becomes 18. One challenge here of course is circular reference, but thanks to the answers I received to my question on StackOverflow regarding this I was able to detect when this is the case and throw an exception before an (appropriate) StackOverflowException occurs.

So I'll cut to the chase. What I'd like to build is a web-based MUD-like system that allows multiple people to interact in an environment that they can have a hand in building. I'd like the syntax to work something like this:

semantic openable has open and closed.
openable property open is not closed.
openable property closed is not open.
openable hearing open sets open and says "You open the @name." when closed; otherwise says "The @name is already open.".
openable hearing close sets closed and says "You close the @name." when open; otherwise says "The @name is already closed.".
openable hearing slam says "You slam the @name." when open; otherwise says "You must open the @name before you can slam it shut.".

The scenario the above demonstrates is the case when a player wants to define a class of behavior (called a Semantic) that represents something that can be opened and closed. I'll write another post soon about what this means and how I'm going to design this system.

Tuesday, November 18, 2008

Configuration Section Designer

For those of you who come here looking for Configuration Section information, I've found a neat (and free) Visual Studio 2008 add-in that provides a graphical interface for designing Configuration Sections - it's called the Configuration Section Designer. I haven't played with it yet, but it comes highly recommended by some on the alt.net list.

Friday, November 14, 2008

Going slow...

Well, the going has been slow. I've been working hard on a shipping provider rewrite for work, and that's sort of sucked the fun out of programming for me lately - especially with the rumors of DHL's demise looming on the horizon. My DHL shipping API integration was my first (and first successful) project with my current job, and to see that 2 months of effort wasted does not help my mood of late.

My plan to write a text adventure game is still brewing. I've been working on story elements - the concept is medieval fantasy, a common staple genre for this sort of game. I'm using the story building as a way to procrastinate, though, and put off building an engine. This sort of thing used to be easy when I was 12 or 13, but every time I start fleshing something out I get mired in objects. Bleh.

Here's the details I've decided upon so far. I will write a text adventure game engine, and the game itself will sit on top of the engine. Where normally I might consider using a database or some sort of configuration DSL, I'm instead going to implement all the rooms, items, npcs, etc., in C# code. This will allow me to implement a great deal of freedom for the player without having to write some sort of scripting language to implement the game in. All the interaction will be handled by the compiled code I write.

So the engine will have things like Room objects, Exit objects, Item objects, NPC objects, etc. The game will implement these things, one for each applicable bit of the game. This sort of thing will allow me, if I so chose, to completely change the rules of the game from room to room. Maybe overkill, but it's the way I want to do it.

So that's what I've been up to. More details later as they develop.

Saturday, October 25, 2008

F# mindblow... simple math expression evaluator

One of the things I typically do when I learn a new programming language is, of course, write a program in it. I try to pick something that will help me understand not just the syntax of the language, but will also help me pick up the style and thinking patterns of the language.

One of the little tasks I typically force upon myself is a simple infix expression evaluator. For the uninitiated, 'infix notation' is the form of notation we humans commonly write our mathematical expression in - that is, the form "a + b * c" etc. Here's a wiki!

Anywho - I decided today was the time for F# to get its own infix evaluator...

Feel free to laugh. I'm laughing at myself, actually - way down inside, in the tiny places, where I harbor my self-loathing and self-doubt, down where I quietly plot my own demise... *ahem*

It took me about 7 hours today to write a total of 95 lines of code. That's ~13 lines of code an hour. Horrible, horrible. Though I'm really not beating myself up as badly as you might think - it took me as long to write this evaluator in VB.NET when I was learning that language (though not nearly as long in C# due to the syntax being the only difference between the languages). I'm just not used to thinking recursively. Sure, I've done recursion in C#, VB.NET, etc., but I've never really used it to replace what would otherwise be imperative-style constructs before. I've only used it when something *had* to be recursive. Also I wanted to adhere to the pure functional programming dogma - zero side effects. This code does indeed adhere to this self-imposed mandate.

Before I post the code, I want to stress that this is *not* optimal code. I know a little about tail recursion, etc., but I *clearly* didn't use it here. I don't even know if I *can* use it here. Also I'm not terribly knowledgeable about the various Seq and List functions that are available, so I probably flubbed them up as well. I don't really care - this works, and I'm proud of it. This is my first major attempt at writing something of any facility in a functional programming language. Also I'd like to mention that I am *very* open to suggestions. If I did something really, truly stupid in here, please call me on it. This is a learning exercise, and I'd like to learn as much as I can from it - part of that is peer review.

So, without further ado, here it is. (Apologies for the different theme - I'm doing this at home and haven't gotten around to installing the darker theme yet.)

    1 #light

    2 

    3 open System

    4 

    5 type operator =

    6   | Add

    7   | Subtract

    8   | Multiply

    9   | Divide

   10 

   11 type token =

   12   | Number of int

   13   | OpenParen

   14   | CloseParen

   15   | Operator of operator

   16 

   17 let tokenize i =

   18   let rec tk s =

   19     match s with

   20     | ' ' :: tail -> tk tail

   21     | '(' :: tail -> OpenParen :: tk tail

   22     | ')' :: tail -> CloseParen :: tk tail

   23     | '+' :: tail -> Operator Add :: tk tail

   24     | '-' :: tail -> Operator Subtract :: tk tail

   25     | '*' :: tail -> Operator Multiply :: tk tail

   26     | '/' :: tail -> Operator Divide :: tk tail

   27     | n :: tail when Char.IsNumber(n) ->

   28       let rec intListToValue (i:int list) acc c =

   29         match i with

   30         | [] -> acc

   31         | n :: tail -> intListToValue tail (acc + (n * int (10.0 ** float c))) (c + 1)

   32       let rec tc (i:int list) (n:char) (s:char list) =

   33         let value = Int32.Parse(string n)

   34         match s with

   35         | n :: tail when Char.IsNumber(n) -> tc (value::i) n tail

   36         | x :: tail -> (Number (intListToValue i value 1)) :: tk (x :: tail)

   37         | [] -> [Number (intListToValue i value 1)]

   38       tc [] n tail

   39 

   40     | [] -> []

   41     | n :: _ -> failwith ("Parse error - invalid character detected: " + n.ToString())

   42   tk (Seq.to_list i)

   43 

   44 let evalTokens input =

   45   let pop2 (stack:'a list) = (stack.Head, stack.Tail.Head, stack.Tail.Tail)

   46 

   47   let eval a b op =

   48     match op with

   49     | Operator Add -> b + a

   50     | Operator Subtract -> b - a

   51     | Operator Multiply -> b * a

   52     | Operator Divide -> b / a

   53     | _ -> failwith "error parsing input"

   54 

   55   let rec eval_rec input numstack (opstack:token list) =

   56     match input with

   57     | Number n :: tail -> eval_rec tail (n::numstack) opstack

   58 

   59     | Operator op :: tail ->

   60       if opstack.Length <> 0 && opstack.Head > (Operator op) then

   61         let firstNum, secondNum, numstackRem = pop2 numstack

   62         let e = eval firstNum secondNum opstack.Head

   63         eval_rec tail (e::numstackRem) (Operator op::opstack.Tail)

   64       else

   65         eval_rec tail numstack (Operator op::opstack)

   66 

   67     | OpenParen :: tail -> eval_rec tail numstack (OpenParen::opstack)

   68 

   69     | CloseParen :: tail ->

   70       match opstack with

   71       | Operator op :: opsTail ->

   72         let firstNum, secondNum, numstackRem = pop2 numstack

   73         let e = eval firstNum secondNum (Operator op)

   74         eval_rec input (e::numstackRem) opsTail

   75       | OpenParen :: _ ->

   76         eval_rec tail numstack opstack.Tail

   77       | _ -> failwith "error parsing input"

   78 

   79     | [] ->

   80       match opstack with

   81       | Operator op :: tail ->

   82         let firstNum, secondNum, numstackRem = pop2 numstack

   83         let e = eval firstNum secondNum (Operator op)

   84         eval_rec [] (e::numstackRem) tail

   85       | [] -> numstack.Head

   86       | _ -> failwith "error parsing input"

   87 

   88   eval_rec input [] []


You call this like so: evaluate "((1 + 2) * 3) / 3" -- this would, of course, evaluate to 3, as expected - it understands and follows the correct order of operations, and respects parenthesis correctly as expected. It doesn't yet handle floats, but I might get around to that at some point. It'll complicate the parsing, but that's not really that big of a deal. The way I'm handling it is weird anyway...

Well there you have it. My first real F# program of any value at all. Despite taking me 7 hours, I'm rather proud of this. It's taught me a great deal, especially that I need to be patient with myself while trying to learn to think in functions. Also, staying pure and functional can be *hard*, especially coming from an imperative / mutable state world. I should also note that my first C# implementation included around 4 times the number of lines of code...

All told, I really enjoyed my dive into F#. My advice to anyone looking into it as a real programming language (and not as a toy) would be to keep an open mind and give it a fair shot.

Tuesday, October 21, 2008

Adventure game via jQuery, AJAX, and MVC

Next quarter, I'm very likely going to be tasked with starting work on the MVC version of our company's public-facing website. It's going to be a massive undertaking, especially for me given how little I know of the company's system. That's okay though. I'm confident that I'll manage get up to speed in that time. I've already made great strides, if I do say so myself.

Meanwhile, one of the real innovations we're going to join in on is the whole jQuery / AJAX / MVC bandwagon. Personally I think this is great - I'm absolutely in love with all three technologies, especially given how easy they are to integrate together. Smitten though I may be, however, I'm most definitely not as proficient with them as I will have to be in order to pursue an undertaking of this magnitude.

To that end, I've decided I'm going to create a fun little project that will hopefully get me up to speed. I am going to write a little adventure game using jQuery, AJAX, and the ASP.NET MVC Framework. When I say adventure game, think Colossal Cave Adventure or Zork. It's not going to be fancy at all, or probably even all that fun for anyone but myself, but that's not the point. I want to use this as a learning tool - and I plan on posting on my progress and insights here.

I'm thinking about starting an open source project for this so you guys can check out my progress, if you want. Meanwhile, I need to think of a name... =)

Configuration Section Handlers via IConfigurationSectionHandler redux

So, it occurs to me that I was pretty lax with my post last month on Configuration Section Handlers and IConfigurationSectionHandler. Sorry for those of you who came to find information and instead got "wow how easy!" - something of a disservice...

Anyway - IConfigurationSectionHandler is an interface in the System.Configuration namespace that, when implemented, allows your software to define and read custom configuration sections. The idea is that you'll put these configuration sections in your app.config or web.config file and permit configuration that doesn't require recompiling your codebase after making changes.

There is another way to handle custom configuration sections - you could inherit from System.Configuration.ConfigurationSection and provide attributes on your properties that you want to be read from configuration. This approach certainly works - there's a writeup on this approach on MSDN here - but I prefer IConfigurationSectionHandler because it affords me more control over the process, even though apparently its use has been deprecated. =(

The first step before you start touching code is to determine the shape of your XML configuration section. I'll use planets as an (admittedly contrived) example:

    1 <planets>

    2     <planet name="Mercury" distanceFromSun=".38"

    3         diameter="4880" mass="3.30e23" />

    4     <planet name="Venus" distanceFromSun=".72"

    5         diameter="12103" mass="4.869e24" />

    6     <planet name="Earth" distanceFromSun="1"

    7         diameter="12756" mass="5.972e24" />

    8     <planet name="Mars" distanceFromSun="1.52"

    9         diameter="6794" mass="6.4219e23" />

   10     <planet name="Jupiter" distanceFromSun="5.2"

   11         diameter="142984" mass="1.900e27" />

   12     <planet name="Saturn" distanceFromSun="9.54"

   13         diameter="120536" mass="5.68e26" />

   14     <planet name="Uranis" distanceFromSun="19.218"

   15         diameter="51118" mass="8.683e25" />

   16     <planet name="Neptune" distanceFromSun="30.06"

   17         diameter="49532" mass="1.0247e26" />

   18     <planet name="Pluto(?)" distanceFromSun="39.5"

   19         diameter="2274" mass="1.27e22" />

   20 </planets>


This is a pretty straightforward bit of XML. A single root 'planets' element that surrounds nine 'planet' elements, each with some attributes - name, distance from the sun (in astronomical units), diameter in kilometers, and mass in kilograms. The next step is deciding how to represent this in your program. Certainly, you could leave it as XML - there's nothing wrong with that - but in practice I find it more likely you'll want to use an object and its properties to hold and manipulate this data. Here's an example:

    1 public class Planet {

    2     public string Name { get; set; }

    3     public float DistanceFromSun { get; set; }

    4     public int Diameter { get; set; }

    5     public float Mass { get; set; }

    6 

    7     public Planet(string name, float distanceFromSun,

    8         int diameter, float mass) {

    9         Name = name;

   10         DistanceFromSun = distanceFromSun;

   11         Diameter = diameter;

   12         Mass = mass;

   13     }

   14 }


This is pretty straightforward so far. All we need now is a way to go from the XML representation to a collection of Planet instances. That's what IConfigurationSectionHandler is for.

In order to do this, your project will need a reference to System.Configuration, if it doesn't have one already. For our Planets configuration, we'll create a new handler called PlanetsConfigurationHandler and with it implement IConfigurationSectionHandler.

IConfigurationSectionHandler is a very small interface. It contains only one method to implement:
object Create(object parent, object configContext, XmlNode section);
As you can see this method is passed a parent object, a context object, and an XmlNode which represents the section itself. Now, I'm going to be completely honest and say that I have no idea what parent and configContext are for. The section parameter is the only one I'm interested in, and it's the only one I've ever used, so I'm going to say it's pretty safe to ignore them for now.

A word of caution. The Configuration system that is responsible for calling your handler will assume that you're not storing any state in your handler, and that it is thread-safe. This means that you really shouldn't use any external or internal state in the body of the Create method. You should assume that your handler will be called multiple times per instance, in random order.

So by this point, all you need to do is write your XML parsing code. For the sake of sanity and simplicity, I'm going to convert this old 1.0-style XmlNode object into a 3.5-style XDocument object, and work with it from there. I prefer to keep up with the current developments in programming languages. If you can't use 3.5 for whatever reason... well, there are plenty of System.Xml references available out there. You're resourceful, you'll find something. ;)

Here's my handler:

    1 public class PlanetsConfigurationHandler

    2     : IConfigurationSectionHandler {

    3 

    4     public object Create(

    5         object parent, object configContext, XmlNode section) {

    6 

    7         XDocument doc = XDocument.Parse(section.OuterXml);

    8         XElement root = (XElement)doc.FirstNode;

    9 

   10         IList<Planet> rList = new List<Planet>();

   11 

   12         foreach (var element in root.Elements() ) {

   13             if (element.Name != "planet")

   14                 throw new ConfigurationErrorsException(

   15                     "planets section only accepts" +

   16                     " 'planet' elements.");

   17 

   18             try {

   19                 string name = element.Attribute("name").Value;

   20                 float distanceFromSun =

   21                     float.Parse(

   22                         element.Attribute("distanceFromSun").Value);

   23                 int diameter =

   24                     int.Parse(

   25                         element.Attribute("diameter").Value);

   26                 float mass =

   27                     float.Parse(

   28                         element.Attribute("mass").Value);

   29 

   30                 Planet newPlanet =

   31                     new Planet(name, distanceFromSun, diameter, mass);

   32 

   33                 rList.Add(newPlanet);

   34             } catch (Exception ex) {

   35                 throw new ConfigurationErrorsException(

   36                     "Error reading planet element."

   37                     , ex);

   38             }

   39         }

   40 

   41         return rList;

   42     }

   43 }


Please excuse the weird formatting - I don't want the code lines to wrap.

So - pretty straightforward. I take the XML section data and using the XDocument elements I parse it for its content. A couple things to notice here: I'm assuming that the root element is correctly named 'planets' - in fact, it's possible it'll be named something else - you'll see how later - so I'm trusting here that the configuration system has passed me the correct section. We'll go with that for now. Second, I am doing some validation on the inner xml - none will be done for me - and I'm making sure that the only thing in my configuration section are 'planet' elements. Third, I've wrapped the rest of the body of the iterator in a try/catch block. I'm using .Parse methods which will throw an exception if the string they're trying to parse is null or malformed - I catch that exception, then throw a ConfigurationErrorsException, passing in the original exception in its constructor to preserve context. This will allow callers of your library to understand what went wrong, when something does.

We've got one last thing to do in order to actually *use* this handler. You've got to register it with the configuration system by adding a bit of XML in the 'Configuration' section:

    1 <configSections>

    2     <section

    3       name="planets"

    4       type="ConfigDemo.PlanetsConfigurationHandler, ConfigDemo"/>

    5 </configSections>


This should be pretty much self-explanatory. This bit of XML tells the configuration system that you've got a custom handler that will handle any sections named 'planets'. Earlier I mentioned that it's possible to use an arbitrary name when dealing with a configuration section. Well, this is where that name is selected. If you change the 'name' attribute's value here, you'll have to use the same value for the name of the section itself - that is, the root element of the section's XML. You'll also need to use that name when you retrieve the section itself - which brings me to my final bit of code:

    1 class Program {

    2     static void Main(string[] args) {

    3         var planets =

    4             (IList<Planet>)

    5             ConfigurationManager.GetSection("asdasd");

    6 

    7         string planetTemplate = "{0}: {1}au, {2}km, {3}kg";

    8 

    9         foreach (var planet in planets) {

   10             Console.WriteLine(

   11                 string.Format(planetTemplate,

   12                 planet.Name,

   13                 planet.DistanceFromSun,

   14                 planet.Diameter,

   15                 planet.Mass)

   16             );

   17         }

   18 

   19         Console.ReadLine();

   20     }

   21 }


This is a console application that retrieves the configuration section 'planets' from App.config, then displays the planets on the console. Very simple. Notice that we need to cast the return from ConfigurationManager.GetSection to the type we expect to receive - that method returns 'object', which is to be expected since it couldn't possibly know what type to expect your handler to return. Once you've got your data out of configuration, it's up to you to decide what to do with it.

So, that's that. I do however have one last thing to say. I've been getting into functional programming quite a bit, and as such I like to exercise those newly-forming muscles any chance I can get. As I mentioned above, the Create method needs to avoid internal or external state. Any time it is given an input (the xml configuration section) it should provide the same output. This sounds an awful lot like it needs to be a pure function, to me - so let's change the method to make it a little more obvious that that's what we're going for:

    1 public class PlanetsConfigurationHandler

    2     : IConfigurationSectionHandler {

    3 

    4     public object Create(

    5         object parent, object configContext, XmlNode section) {

    6         XDocument doc = XDocument.Parse(section.OuterXml);

    7         XElement root = (XElement)doc.FirstNode;

    8 

    9         if (root.Descendants().Any(e => e.Name != "planet"))

   10             throw new ConfigurationErrorsException(

   11                 "planets section only accepts" +

   12                 " 'planet' elements.");

   13 

   14         try {

   15             return

   16                 (from p in root.Descendants()

   17                 let newPlanet = new Planet(

   18                     p.Attribute("name").Value,

   19                     float.Parse(p.Attribute("distanceFromSun").Value),

   20                     int.Parse(p.Attribute("diameter").Value),

   21                     float.Parse(p.Attribute("mass").Value)

   22                 )

   23                 select newPlanet).ToList();

   24         } catch (Exception ex) {

   25             throw new ConfigurationErrorsException(

   26                 "Error reading planet element."

   27                 , ex);

   28         }

   29     }

   30 }


Whoa. Way different - and yet the functionality is the same. Much fewer lines of code here, as well. I'll leave it as an exercise to the reader to work this out, if it's not already apparent - it's not a very tough query, really. I have faith. :)

Good luck with your own IConfigurationSectionHandler implementations - feel free to shoot me any questions you may have about the process, and I'll answer as best I can.


kick it on DotNetKicks.com