Cool stuff in FubuCore No. 3: Static Reflection

This is the third post of the FubuCore series mentioned in the Introduction post.

NOTE: In case you weren’t aware, FubuCore is available as a Nuget package and is completely independent from FubuMVC. Other projects besides FubuMVC use it, such as Storyteller which has nothing to do with FubuMVC.

Static reflection.

Ayende was doing it back in 2005 (before .NET 3.5!)

Daniel Cazzulino (kzu) was doing it with linq back in 2007.

Jeremy Miller started playing with it and had the idea to use it to eliminate XML configuration from our NHibernate mappings.  James Gregory picked it up and it is now known as Fluent NHibernate. James later wrote a good post on the subject titled “Introduction to static reflection.”

Static reflection can be summarized simply as: Using the Reflection API, without using strings, by using the delayed execution features of Linq in order to get a Reflection/metadata reference to a code element (property, method, etc).

This technique of not using magic strings (either in code or XML) to represent code constructs (type names, method names, property names, etc) started catching on and can now be found in numerous projects, including ASP.NET MVC.

A simple example of where you might use it is if you want to render some HTML having to do with the property on one of your models.  For example, Model.FirstName.  You could just have a method like:  “TextBoxFor(Model.FirstName)” which would render a textbox. The problem is, TextBoxFor only gets the *value* of FirstName. It doesn’t know any of the metadata about FirstName.  What if we wanted to do some conventional stuff like slap a “required” CSS class on input element so that our validation framework could attach validation behavior to it? What if we had authorization in our app that prevented you from editing certain fields if you didn’t have the privilege?  If our TextBoxFor method were smart enough and had the metadata for FirstName, it could run it through an authorization checker to see if it should slap a “readonly” attribute on the textbox or not.  So you see, having more than just the value can really help. But how do we pass a reference to the FirstName property itself, instead of just the value?  This is what static reflection is for.

We use it extensively in almost all our projects at Dovetail.  It’s core to StructureMap, Storyteller, and FubuMVC.  One of the biggest features of FubuMVC is that it works with the fact that you’re in a strongly, statically-typed environment. In Rails, everything is a string and that’s OK.  Anyone who’s worked on a large project, however, knows that managing strings-as-route-identifiers can get problematic (yes, even in Rails, praise be upon it). BEFORE YOU FLAME – I’m not saying that Fubu is better than Rails or anything like that. ASP.NET MVC has the same problem. In FubuMVC, we wanted to take as much advantage of strong typing as possible (hey, if we’re going to be using C#, let’s make the most of it, right?).  We wanted routes to be ReSharper-navigable (CTRL+click or CTRL+B navigation) and we wanted easy rename support (F2 rename refactoring).

This has paid for itself as we’ve been able to significantly rearrange our routes several times in the life of our product with little to no thrashing through views.  Also, by not using magic strings, we can get a full, complete list of all our routes, at config-time to be able to do things like advanced diagnostics (Joshua Flanagan also showed diagnostics in action). We were doing it years before the Glimpse guys were, by the way (but they do some cool stuff that Fubu could integrate with, so I look forward to seeing that integration one day).  On a big project (where “big” means dozens of routes, runtime-loaded packages with their own routes and views being added to the app, etc), having the ability to see all the possible routes and how they’re wired up at config-time is invaluable.

But I digress. Static reflection is a really useful tool if you happen to be working in a statically-typed environment as it can help you take advantage of all the typing data the compiler knows about at compile-time.

Now that I’ve hopefully sold you  on the idea that static reflection is useful and profitable when in a statically-typed environment, I’ll show you how you can use FubuCore to bring it to reality in your project.

How it works

Remember our TextBoxFor example earlier? The signature, before static reflection, might look like this:

public string TextBoxFor(object value);

But now, it will look like this:

public string TextBoxFor<T>(Expression<Func<T,object>> expression);

That “Expression<>” business is the key. This tells the compiler to treat this as metadata. It doesn’t actually *compile* the Func<T,object>, it returns a new type of object called a System.Linq.Expressions.Expression that represents all the metadata the compiler had about this expression that it would’ve normally used to actually compile the code. But instead it stopped there and turned all that metadata into an “Expression Tree”.  Using this, we can get all the reflection data you’d otherwise get with Type.GetMethod or Type.GetProperty using the method or property name as a string. Using static reflection is a lot faster than dynamic reflection because the compiler has already done the work of looking everything up at compile-time. There’s no parsing strings and looking through the assembly metadata to try to find the MethodInfo or PropertyInfo by name.

There’s still a small chunk of work left to turn an Expression into a MethodInfo or PropertyInfo. That’s where ReflectionHelper comes in…

ReflectionHelper

All the magic starts with a little static helper class known as “ReflectionHelper.”  This has some helpful methods on it like GetMethod, GetProperty, and GetAccessor.

Inside our method (i.e. TextBoxFor), we will have the “expression” variable which is of type System.Linq.Expressions.Expression.  If we know the expression references a method, we can use ReflectionHelper.GetMethod. If we know it represents a property, we can use ReflectionHelper.GetProperty. Otherwise, if we don’t know for sure, we can use ReflectionHelper.GetAccessor and then interrogate the result to see whether it’s a method or property.

So our TextBoxFor method might look something like:

public string TextBoxFor<T>(Expression<Func<T,object>> expression)
{
    // Get the metadata
    var property = ReflectionHelper.GetProperty(expression);
    // Get the actual value from the 
    var value = expression.Compile()(_model);
    // Generate the HTML with the metadata and value
    return generateHtml(property, value);
}

 

Assuming we have a strongly-typed view that already knows its model type (let’s say it’s a type called ViewUserModel for the view ViewUser.aspx), we could call our TextBoxFor like this:

<%= this.TextBoxFor(model => model.FirstName); %>

With the actual PropertyInfo from GetProperty and the value retrieved, we have everything we need to generate the proper HTML to render a textbox for this property including any validation or read-only attributes.

Accessor

I mentioned earlier that calling ReflectionHelper.GetAccessor can be used if you’re unsure whether the Expression that was passed in is a method or a property. It has another important use: Expressions with a chain of properties.

If you use GetAccessor, you can get the whole chain of properties so you can inspect each property in the chain, if necessary. Using GetAccessor, our TextBoxFor could get a lot smarter and be able to handle situations like this:

<%= this.TextBoxFor(model => model.Case.Owner.FirstName); %>

 

The interface that comes back from GetAccessor is called, coincidentally enough, Accessor.  It has some nifty methods on it such as GetValue and SetValue. But the best part of it (for property chains, at least), is the PropertyNames property which returns a string[] of all the names in the chain.  If you wanted to walk the chain yourself and inspect them, you can call  the Getters() method which will return a list of IValueGetters which may be PropertyValueGetters or MethodValueGetters.  You can then query the IValueGetter for the name or call GetValue to get the value at that point in the chain.

Summary

There’s lots more that could be said for static reflection, but this is enough hopefully to get you started and thinking about it.  If you want to see how static reflection can be used for serious fun and profit, you can look at some of the examples in FubuMVC, Fluent Nhibernate, ASP.NET MVC, and others.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Chad Myers

Chad Myers is the Director of Development for Dovetail Software, in Austin, TX, where he leads a premiere software team building complex enterprise software products. Chad is a .NET software developer specializing in enterprise software designs and architectures. He has over 12 years of software development experience and a proven track record of Agile, test-driven project leadership using both Microsoft and open source tools. He is a community leader who speaks at the Austin .NET User's Group, the ADNUG Code Camp, and participates in various development communities and open source projects.
This entry was posted in .NET, cool-stuff-in-fubu, fubucore, FubuMVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • Marco

    Thanks! Can we expect blog post like this about FubuMVC?

    • http://chadmyers.lostechies.com Chad Myers

      Yep. I’ve got about 10 posts total planned for the “FubuCore” series and about 12 for the “FubuMVC” series

      • Marco

        Nice! Thanks

  • Pingback: The Morning Brew - Chris Alcock » The Morning Brew #864

  • Chris

    Great post. And I really think your writing style has improved a lot too. Good work!

  • Malisa Ncube

    Excellent post. I have a lesson learned from this.

  • Anonymous

    Very helpful.   Thanks for taking the time to put this together Chad.

  • http://charlesstrahan.com/blog/ Charles Strahan

    Good ol’ homoiconicity!

  • http://nieve.myopenid.com/ nieve

    Hey Chad,
    Can this code (html conventions & tags) be then afterwards reused in your acceptance tests to get less brittle and more resharper-navigable/renameable tests?

    • http://chadmyers.lostechies.com Chad Myers

      Not sure I follow

      • Anonymous

        Ok, sorry about that, let me try be more coherent:
        So suppose you use selenium to test your application. One of the pains in writing a maintainable test is having to worry about the component/s under test- that is their xpath/id/className/css selector… I was sort of thinking out loud whether we could use static reflection, and maybe even use the same conventions that we use when creating the html (with TextBoxFor) inside our acceptance tests to get to these text boxes, labels, drop downs etc’…

        • http://chadmyers.lostechies.com Chad Myers

          Ah,yes. That’s exactly what we do with StoryTeller in our project at Dovetail.  Our StoryTeller fixtures know about our Html conventions and knows how ID’s are generated and can use those conventions. It makes it much less brittle.

  • Anonymous

    I think this library could solve a problem I’m having, but I’m still digging through things.

    A particular class has several string properties with the substring “qualifiers”, is it possible to leverage this library to append a char to those fields? 

    Thanks for the excellent work on this series, it is much appreciated.

    • http://chadmyers.lostechies.com Chad Myers

      @kevdog I’m not sure what you mean by “with the substring ‘qualifiers’”. Could you please clarify that statement so I understand precisely what you mean (and therefore give you a better answer)?

      • Anonymous

        I need to set every property that has “qualifiers” in its name to the same value. There are some edge cases, but that’s the base case.

        • http://chadmyers.lostechies.com Chad Myers

          @kevdog:  Ah, I see.  No, that’s the opposite of what Static Reflection does. What you’re wanting is what traditional string-based reflection does.  I’d just do a standard yourType.GetProperties().Where(p => p.Name.ToLower().Contains(“qualifiers”)).Each(p => p.SetValue(…));