21 May 2008

Implementation of the Visitor pattern using .NET Generics

In a recent post I discussed using the Visitor pattern to solve a lazy initialization problem in NHibernate. The example Visitor class in that post is tied to the base class of the class hierarchy it is dealing with so everywhere you need to use a Visitor class you'd need to define at least one of these Visitor classes and then possibly inherit from it to implement alternative functionality.

A better solution is to use .NET Generics to create the Visitor e.g.:

// Visitor for base type TBase
public class Visitor<TBase>
{

 // Delegate for type TSub which can be any subclass of TBase
 // that takes a parameter of type TSub
 public delegate void VisitDelegate<TSub>(TSub u) where TSub : TBase;
 
 // Dictionary to contain our delegates
 Dictionary<Type, object> vDels = new Dictionary<Type, object>();
 
 // Method to add a delegate for type TSub which can be any subclass of TBase
 public void AddDelegate<TSub>(VisitDelegate<TSub> del) where TSub : TBase
 {
  vDels.Add(typeof(TSub), del);
 }
 
 // Visit method for type TSub which can be any subclass of TBase
 // takes one parameter of type TSub, picks the right delegate
 // and executes it passing the parameter to it
 public void Visit<TSub>(TSub x) where TSub : TBase
 {
  if(vDels.ContainsKey(typeof(TSub)))
  {
   ((VisitDelegate<TSub>)vDels[typeof(TSub)])(x);
  }
 }
 
}

I've knocked up a quick Snippet Compiler demo here. The key parts are the Accept methods in the classes of the hierarchy...

public class Cat : Mammal
{
 ...
 public override void Accept(Visitor<Mammal> visitor)
 {
  visitor.Visit<Cat>(this);
 }
}

...and adding the actual work to be done by creating delegate for each of the types you want to "capture"...

// Our visitor on our base class which will do our type specific work
Visitor<Mammal> visitor = new Visitor<Mammal>();
string outerVar = "A variable from outside delegate";

// Add the work to be done for DomesticCat
visitor.AddDelegate<DomesticCat>(delegate(DomesticCat a){
 WL("Doing some DomesticCat specific work");
 WL(a.Age + ", " + a.Color + ", " + a.Name);
 WL(outerVar);
});

// Add the work to be done for Dog
visitor.AddDelegate<Dog>(delegate(Dog b){
 WL("Doing some Dog specific work");
 WL(b.Age + ", " + b.Color);
});

The visitor pattern is quite widely applicable in OO environments however, while this solution may not be ideal where you need the visitor class to have a lot more information about the task it is to perform, it is certainly preferable to a large if...else if...else... type construct you might otherwise use for small tasks.

20 May 2008

dp.SyntaxHighlighter jQuery plugin

I've just added syntax highlighing to the code samples on my blog using the excellent dp.SyntaxHighlighter. Adding a class name e.g. "c#" or "xml" to your pre or textarea elements and calling HighlightAll magically highlights the content and turns the surrounding element into a fancy box complete with toolbar.

I tend to wrap my samples in a <pre><code>...</code></pre> so applying the highlight on the pre tag would have broken because of the additional code inside. A quick gander at the code, bit of refactoring in shCore.js and a jQuery one-liner later and I've got a nice(ish) plugin that will apply highlighting to the elements selected through jQuery thusly:

$(document).ready(function(){
   $("code").syntaxHighlight({showGutter: false, firstLine: 5});
});

The settings are:

  • showGutter < bool >
  • showControls < bool >
  • collapseAll < bool >
  • firstLine < int >
  • showColumns < bool >

You can grab the files from here:

This mod is using the latest stable release (1.5.1) of dp.SyntaxHighlighter. It looks like version 1.6 is in the pipeline with some major changes so I'll keep an eye on that and maybe revisit this when it comes out.

16 May 2008

Implicit polymorphism and lazy collections in NHibernate

If you create a lazy loaded property or collection in NHibernate which can contain any type from a class hierarchy, for example by having mappings like this:

<?xml version="1.0" encoding="utf-8"?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2">
  <class name="Mammal" table="Mammal">
    <discriminator column="mammal_type" type="String"/>
    ...
    <subclass name="Cat" discriminator-value="CAT">
      ...
      <subclass name="DomesticCat" discriminator-value="CAT-DOMESTIC">
        ...
      </subclass>
    </subclass>
    <subclass name="Dog" discriminator-value="DOG">
      ...
    </subclass>
  </class>
  <class name="Zoo" table="Zoo">
    ...
    <bag name="Animals">
      <key column="zoo_fkey"/>
      <one-to-many class="Mammal"/>
    </bag>
  </class>
</hibernate-mapping>

You'll find that on requesting your objects from your collection they will be of a special new type NHibernate has created, derived from your base class which in this case is "Mammal".

This is a real problem because it means that you can't perform is or as operations on it to determine which actual type it is and you can't cast it to access properties and methods of your derived types.

The solution is to use the Visitor pattern which is described in detail on this site with a couple of examples in C# on this site. Essentially it involves creating a class with a method which is overloaded for each of the types in your class hierarchy.

class MammalVisitor
{
  public void Visit(Cat c) { ... Cat operations ... }
  public void Visit(DomesticCat dc) { ... DomesticCat operations ... }
  public void Visit(Dog d) { ... Dog operations ... }
}

This "visitor" object is then passed to a method defined on the base class of your hierarchy and then subsequently overridden on each derived type.

class Mammal
{
  public virtual void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...
}

class Cat : Mammal
{
  public override void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...  
}

class Dog : Mammal
{
  public override void Accept(MammalVisitor mv) { mv.Visit(this); }
  ...  
}

These methods simply call the visitor's method passing this to it which in turn will automatically execute the correct overload.

Mammal m; // some unknown derived type of mammal
MammalVisitor mv = new MammalVisitor();
m.Accept(mv);

These overloaded methods can then perform your type specific functions. In the example above you have no knowledge of the type of Mammal that you have however when you call Accept the relevant code is automatically executed. If Mammal happens to be a Cat type then the Cat overloaded Visit method is called.

13 May 2008

Creating Views using XSL in ASP.NET MVC

There's something about Web Forms that never felt quite right to me; it all seemed a bit too much like a bodge that created more problems than it solved. I've been having a tinker with ASP.NET MVC for the past few days now and I'm really liking the way it all fits together; giving you clean separation between the layers and a means of passing data between them.

The View layer in MVC uses a very Classic ASP-esque markup for mixing code and HTML. Seems rather dirty but by this point any major processing should have been done and all that you'll need to do is render HTML with maybe some looping.

That being said if all we'll need to do by this point is some looping at the most then why not use an XSL transform instead?

XSL is well defined and established now with a load of tools out there for giving you a WYSIWYG view of your tranform as you build it. Plus as it is purely XML based it will likely be a lot easier for designers (the folk who we really want to build Views) to get to grips with.

A quick proof of concept

Step 1 - Create a model class for your XSL ViewData

This has simply an XmlDocument which will contain our serialized object and a string which will contain a path to our XSL file.

public class XslViewData
{
 private System.Xml.XmlDocument _doc;
 private string _xslPath;

 public XslViewData(System.Xml.XmlDocument doc, string xslPath)
 {
  _doc = doc;
  _xslPath = xslPath;
 }
  
 public System.Xml.XmlDocument Doc
 {
  get 
  {
   return _doc;
  }
 }

 public string XslPath
 {
  get
  {
   return _xslPath;
  }
 }
}

Step 2 - Serialize your object to XML in your Controller

First make sure the type you want to render is ready for XML serialization. This involves adding some attributes to classes and properties so read up on that first before you carry on. It's important to get your type serializing out in a nice way as it will be easier to work with in the XSL.

using System.Xml;
using System.Xml.Serialization;
...
Product prod = ProductRepository.GetProduct(id);
XmlSerializer ser = new XmlSerializer(typeof(Product));  
XmlDocument doc = new XmlDocument();
System.IO.MemoryStream ms = new System.IO.MemoryStream();
XmlWriter xw = XmlWriter.Create(ms);
ser.Serialize(xw, prod);
ms.Position = 0;
doc.Load(XmlReader.Create(ms));
RenderView("Xsl", new XslViewData(doc, "/Content/prodDetail.xsl"));

Step 3 - Create a ViewPage or ViewUserControl to host your XSL

All you need in the aspx/ascx file is an Xml ASP.NET control...

<asp:Xml ID="Xml1" runat="server" onload="Xml1_Load"></asp:Xml>

...and in the code behind...

public partial class Xsl : ViewPage<XslViewData>
{
 protected void Xml1_Load(object sender, EventArgs e)
 {
  Xml1.Document = ViewData.Doc;
  Xml1.TransformSource = ViewData.XslPath;
 }
}

Step 4 - Create an XSL file

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
 
 <xsl:template match="/Product">
  <h2><xsl:value-of select="Name"/></h2>
  <xsl:apply-templates select="Image"/>
    </xsl:template>

 <xsl:template match="Image">
  <img>
   <xsl:attribute name="src">
    <xsl:value-of select="ImageUrl"/>
   </xsl:attribute>
  </img>
 </xsl:template>
 
 <xsl:template match="*">
 </xsl:template>
 
</xsl:stylesheet>

Done

Not only is this simple to implement it has a lot of scope for improvment; compiling transforms, adding caching and configuation etc. This method also has the advantage that it requires no recompile to alter the template.

Links