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.