Digging around: Analysing ASP.NET MVC2 FastTrack expressions

This is a third companion post to Scott Guthrie’s ASP.NET MVC 2: Strongly Typed Html Helpers.

Today instead of reading code, I’d thought I’d write some. I threw together a class which does the analysis performed by the FastTrack class in ASP.NET MVC2. To recap – the FastTrack class:

  • decides if an expression can be “fast tracked”
  • if it can – builds, compiles and caches it
  • returns the cached expression in future calls

This code demonstrates the bit that does the deciding, and gives us something to play around with.

using System;
using System.Linq.Expressions;

namespace MvcHarness
{
  public class FastTrackAnalyser<TModel>
  {
    public void Analyse<TValue>(Expression<Func<TModel, TValue>> lambda)
    {
      ParameterExpression modelParameter = lambda.Parameters[0];
      Expression body = lambda.Body;

      if (modelParameter == body)
      {
        Console.WriteLine("{0} is a function returning its own argument", lambda);
        return;
      }

      ConstantExpression constantExpression = body as ConstantExpression;
      if (constantExpression != null)
      {
        Console.WriteLine("{0} is a function returning a constant value", lambda);
        return;
      }

      MemberExpression memberExpression = body as MemberExpression;
      if (memberExpression != null)
      {
        if (memberExpression.Expression == null)
        {
          Console.WriteLine("{0} is a function returning a static member of either the model or another type", lambda);
          return;
        }

        if (memberExpression.Expression == modelParameter)
        {
          Console.WriteLine("{0} is a function returning a member of the model", lambda);
          return;
        }

        ConstantExpression constantExpression2 = memberExpression.Expression as ConstantExpression;
        if (constantExpression2 != null)
        {
          Console.WriteLine("{0} is a function representing a captured local variable", lambda);
          return;
        }
      }
      Console.WriteLine("{0} cannot be fast tracked", lambda);
    }
  }
}


I called it like this (with output inline in the comments):

using System;

namespace MvcHarness
{
  class Program
  {
    static void Main(string[] args)
    {
      FastTrackAnalyser<string> analyser = new FastTrackAnalyser<string>();

      analyser.Analyse(x => x);
      // outputs "x => x is a function returning its own argument"

      analyser.Analyse(x => 999);
      // outputs "x => 999 is a function returning a constant value"

      analyser.Analyse(x => String.Empty);
      // outputs "x => String.Empty is a function returning a static member of either the model or another type"

      analyser.Analyse(x => x.Length);
      // outputs "x => x.Length is a function returning a member of the model"

      string name = "Joe Field";
      analyser.Analyse(x => name);
      // outputs "x => value(MvcHarness.Program+<>c__DisplayClass0).name is a function representing a captured local variable"

      analyser.Analyse(x => name.Length);
      // outputs "x => value(MvcHarness.Program+<>c__DisplayClass0).name.Length cannot be fast tracked"
    }
  }
}

The really interesting calls are the last two. They are analysing expressions which use captured local variables. The first one succeeds, but the second fails because it attempts to access a member of the variable.

Leave a Reply

Your email address will not be published. Required fields are marked *