Exploring FubuCore: Convert a string value to any type of .Net class with the ObjectConverter

Several months ago the Dovetail team realized that our various OSS projects and our main codebase were starting to show a lot of duplication of utilities and extension methods. At one time ReSharper could find 6 different versions of a Cache<TKey, TValue> utility that we had originally written for what became Fluent NHibernate and at least 4-5 versions of the pesky IEnumerable<T>.Each() extension method that we all add to our new projects on day 1 (because some ivory tower guy at Microsoft had a dogmatic objection to that very extension and refused to put it into the BCL where it belongs).  Worse yet was the fact that I was finding myself needing to fix certain extension methods across several different projects.  The obvious answer was to consolidate many of our commonly used utilities and extension methods into a common library which we called “FubuCore” in the greater FubuMVC project.  I think there’s some potentially useful stuff in there that other teams could use or contribute to, so here’s to the start of a new series on the FubuCore library starting with the sleek, sexy ObjectConverter class that I use heavily in StoryTeller and our Dovetail code:

    public interface IObjectConverter
    {
        // Given a string and a .Net type, read this string
        // and give me back a corresponding instance of that
        // type
        object FromString(string stringValue, Type type);
        T FromString<T>(string stringValue);


        bool CanBeParsed(Type type);
    }

The real class behind this deceptively simple interface can take a string value and return to you an instance of the type you requested.  Pretty awesomely boring, right?  The TypeDescriptor and TypeConverter classes built into the BCL already does some of this (and by default ObjectConverter delegates to TypeDescriptor to handle most simple types), but they’re somewhat clunky to use.  No, the cool part about the underlying ObjectConverter object is that you can teach it how to convert a string to an entirely new type that you just created.  I always thought the old fashioned class oriented approach that FitNesse took was clumsy and high ceremony, so I decided to just register a Lambda of type Func<string, T> for a given T like this method on ObjectConverter:

        public void RegisterConverter<T>(Func<string, T> finder)
        {
            _froms[typeof(T)] = x => finder(x);
        }

The value of the Lambda approach is that you can add a small strategy to ObjectConverter inline without going to the trouble of defining another class that’ll live somewhere off to the side.

 

Putting ObjectConverter to Work

Let’s say that you have a value type in your system called Contact like this:

    public class Contact
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }

And you want to represent this in string form as “FirstName LastName” like “Jeremy Miller.”  You can quite happily teach ObjectConverter how to convert a string to a Contact object with the code from this unit test:

        [Test]
        public void register_and_retrieve_a_new_type_of_complex_object()
        {
            var finder = new ObjectConverter();
            finder.RegisterConverter<Contact>(text =>
            {
                var parts = text.Split(' ');
                return new Contact(){
                    FirstName = parts[0],
                    LastName = parts[1]
                };
            });

            var c = finder.FromString<Contact>("Jeremy Miller");

            c.FirstName.ShouldEqual("Jeremy");
            c.LastName.ShouldEqual("Miller");
        }

Simple enough, eh?  Now, how about if we want to get an array (or IEnumerable) of Contact objects from a string?  No problem, by default ObjectConverter can take a comma delimited string and convert each value into a Contact like this:

        [Test]
        public void how_about_getting_an_array_of_those_complex_objects()
        {
            // Same converter as before
            var finder = new ObjectConverter();
            finder.RegisterConverter<Contact>(text =>
            {
                var parts = text.Split(' ');
                return new Contact()
                {
                    FirstName = parts[0],
                    LastName = parts[1]
                };
            });

            // Now, let's pull an array of Contact's
            var contacts =
                finder.FromString<Contact[]>("Jeremy Miller, Rod Paddock, Chad Myers");
       
            contacts.Select(x => x.LastName)
                .ShouldHaveTheSameElementsAs("Miller", "Paddock", "Myers");
        }

Look at that, once I defined how to find a Contact from a string, ObjectConverter now knows how to handle an array (or IEnumerable / IList / List) of Contact’s as well.  That little feature has been very helpful to me in creating better StoryTeller DSL’s.

 

“Finding” Objects

I originally wrote ObjectConverter (née ObjectFinder in older versions) as a utility internal to the new StoryTeller testing engine.  I knew from my prior experiences with FitNesse that I’d need to frequently take test input data that would be stored as strings and convert that string to the real .Net types that the test code would need to do its job.  I also knew that I’d need to allow users to “teach” StoryTeller how to convert (or find) new types of objects from the domain of the system under test so that StoryTeller could take a set of key/value pairs of strings and turn that into the correct arguments to call a method like this one from Dovetail test harness code:

        // 'User' and 'Site' are both Entity types
        // in our system
        [FormatAs("User {user} is at Site {site}")]
        public void UserIsAtSite(User user, Site site)
        {
            user.Site = site;
            _system.Save(user);
        }

In the StoryTeller tests we can just specify the user name and the site name, but first we had to teach ObjectConverter how to find a user and site from a string with a function that:

  1. First tries to look up an existing User by the specified user name, and if it exists, return they existing user object
  2. If the user doesn’t already exist, create a new User with that user name and some default data, save it, and return the new User object

Using ObjectConverter within StoryTeller tests like this has done a world of good for us by making test input setup less laborious and making our tests much easier to understand and read because there’s less “noise” in the “Arrange” part of our StoryTeller tests.

 

 

Family of Types in One Swath

Instead of explicitly telling ObjectConverter how to deal with each specific type, you might be able to make your life easier by registering a single IObjectConverterFamily policy that can tell the ObjectConverter how to deal with several types at once.  Let’s just look at the interface:

    public interface IObjectConverterFamily
    {
        // ObjectConverter calls this method on unknown types
        // to ask an IObjectConverterFamily if it "knows" how
        // to convert a string into the given type
        bool Matches(Type type, IObjectConverter converter);

        // If Matches() returns true for a given type,
        // ObjectConverter asks this IObjectConverterFamily
        // for a converter Lambda and calls its
        // RegisterFinder() method behind the scenes to cache
        // the Lambda for later usage
        Func<string, object> CreateConverter(Type type, Cache<Type, Func<string, object>> converters);
    }

Deep in the guts of our proprietary (sounds special if you say it like that) rules engine we frequently need to reference an entity as part of a Json blob and find the correct entity later (think of rules like “send this case over to the urgent queue” where the Queue is an Entity in our Domain Model).  Like many projects we use a Layer Supertype class for our Entity objects for all the basic properties like Id.  Since all our Entities are identified the same way, we can tell an instance of ObjectConverter to convert a string to any type that inherits from Entity by looking up that entity in our Repository by Id in this code:

    public class DomainEntityConverterFamily : IObjectConverterFamily
    {
        private readonly IRepository _repository;

        public DomainEntityConverterFamily(IRepository repository)
        {
            _repository = repository;
        }

        // Matches any type deriving from DomainEntity
        // CanBeCastTo<> is an extension method in FubuCore as well
        public bool Matches(Type type, IObjectConverter converter)
        {
            return type.CanBeCastTo<DomainEntity>();
        }

        // In this case we find the correct object by looking it up by Id
        // from our repository
        public Func<string, object> CreateConverter(Type type, Cache<Type, Func<string, object>> converters)
        {
            return text =>
            {
                var guid = new Guid(text);
                return _repository.Find(type, guid);
            };
        }
    }

I can register the conversion family by just calling the RegisterConverterFamily<T>() method on ObjectConverter.

What else can ObjectConverter do?

Rather than make this blog post longer than its already absurd length, I’d invite you to simply look at the unit test class for ObjectConverter here.  If you’re interested in that sort of thing, I’d put ObjectConverter forward as a somewhat advanced example of using first class functions as the primary unit of composition.

About Jeremy Miller

Jeremy is the Chief Software Architect at Dovetail Software, the coolest ISV in Austin. Jeremy began his IT career writing "Shadow IT" applications to automate his engineering documentation, then wandered into software development because it looked like more fun. Jeremy is the author of the open source StructureMap tool for Dependency Injection with .Net, StoryTeller for supercharged acceptance testing in .Net, and one of the principal developers behind FubuMVC. Jeremy's thoughts on all things software can be found at The Shade Tree Developer at http://codebetter.com/jeremymiller.
This entry was posted in FubuMVC, StoryTeller. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.calabonga.com Calabonga

    Very good article! Thanks!

  • http://www.calabonga.com Calabonga

    Very good article. Thanks!

  • http://notesdotnet.wordpress.com/ nieve

    Jeremy,
    out of ignorance, why not use some Linq Expression.Assign, even as a fallback mechanism, that would take strings with properties names and values? Why wouldn’t it be just as good?

  • http://www.hanselman.com Scott Hanselman

    What happens if someone has only one name? How do you handle parsing errors?

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

    @Dirk: It depends where the strings are coming from.

    If we used strings a lot throughout our code, then yes that would be “magic strings” and would harm type safety.

    But the strings are usually coming from:
    - File dumps from external systems (i.e. CSV import)

    - Acceptance tests where type safety is not preferred (to allow the code to change out from underneath the tests without necessarily breaking the tests)

    - Denormalized data stored in search indexes and reporting databases

    And a few other things which are escaping me right now.

    Basically, we kept running into various situations where we had a string representation of an object from somewhere and we needed to turn it back into a strongly typed object.

  • Dirk

    It was more of a question really, as I think it is preaty neat.

    But doesn’t it remove type safety?

  • http://codebetter.com/members/jmiller/default.aspx Jeremy D. Miller

    @Dirk,

    I don’t know how you would say this is related to “magic strings”. We’re using ObjectConverter to easily turn external data into objects, that’s not magic strings at all.

  • Dirk

    Jeremy great example of using Lamdas, but isn’t this just a fancy way to justify magic strings?

  • http://beletsky.net/ Alexander Beletsky

    It looks good! In many projects you have to do similar to this, so it would be great if such functionality could be packaged in one open source assembly :)

    Thanks,

  • http://www.servicestack.net/mythz_blog/ Demis Bellot

    Very Nice.

    I actually have developed something similar basically it can serialize any POCO type to a string and back *very quickly*, I have a blog post with more info at:
    http://www.servicestack.net/mythz_blog/?p=176

    It also comes with a super handy T.Dump() extension method that is similar to php’s print_r() that recursively dumps the contents of any type into a human readable text format:
    http://www.servicestack.net/mythz_blog/?p=202