Thursday, March 20, 2008

LinFu.DynamicModel, MxClone, and the Art of Adaptive Object Models

I've done it! :) Both the LinFu.DynamicModel and the MxClone (the MyXaml Engine Clone) libraries are ready for production use, and I can't wait to get started on writing the CP articles for both libraries.

A Tale of Two Approaches

As I mentioned in previous posts, LinFu.DynamicModel allows you to dynamically create an entire object model in memory at runtime without having to recompile your application. With LinFu.DynamicModel, you can either construct the model directly through code, or you can use the MxClone to create the model for you, using XML markup. I'll briefly go over each approach in the following sections, but before I do that, let's take a look at the interface implementation that we're going to dynamically generate:

A Canonical Approach: The Person Interface

Let's suppose that I wanted to dynamically create a dynamic type that looks like the following interface:

public interface IPerson
{
int Age { get; set; }
string Name { get; set; }
}

Using LinFu.DynamicModel in Your Code

Here's how you can dynamically create a type that implements the IPerson interface:

// TypeSpec objects are type descriptions that can be modified at runtime
TypeSpec personSpec = new TypeSpec()
{
Name="PersonType",

// Notice the strongly-typed properties
Properties =
{
new Property<int>("Age"),
new Property<string>("Name")
},
};

// This will return true
bool isPerson = personSpec.LooksLike<IPerson>();
var person = personSpec.CreateDuck<IPerson>();

// Use the person object just like any other POCO
person.Age = 18;
person.Name = "Me";
// ...


Thanks to C#'s 3.0 new language features, you can easily create a model in memory with LinFu in relatively few lines of code. What makes this particularly interesting, however, is the fact that as the given TypeSpec changes, all of the IPerson instances that rely on that TypeSpec automatically "change" their behavior to match the newly-modified Person TypeSpec.

Using LinFu.DynamicModel with MxClone

Needless to say, there's a myriad of things you can do with this sort of technology, but it gets better--you can describe the same model through XML, using a MyXaml-style syntax:

<?xml version="1.0" encoding="utf-8"?>
<Root xmlns="LinFu.Reflection.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
xmlns:def="Definition" xmlns:set="Setters">
<TypeSpec def:Name="PersonType" Name="PersonType">
<Properties>
<PropertySpec PropertyName="Name"
PropertyType="System.String">
<set:Behavior>
<PropertyBag/>
</set:Behavior>
</PropertySpec>
<PropertySpec PropertyName="Age"
PropertyType="System.Int32">
<set:Behavior>
<PropertyBag/>
</set:Behavior>
</PropertySpec>

</Properties>
</TypeSpec>

</Root>


As you can see, the XML syntax for MxClone is similar to MyXaml, with the exception of the set:Behavior element. MxClone allows you to assign object references to properties without having to give it a specific reference name (e.g., {SomeName}), and in this case, the set:Behavior element means that I'm assigning an object reference of type 'PropertyBag' to a property named "Behavior" on the PropertySpec type. (The PropertyBag class, in turn, is responsible for maintaining the state of each property on every given type instance--but for now, I'll save that for the upcoming LinFu article on CP)

In essence, MxClone is actually constructing the same TypeSpec in memory using XML markup. Having the model specified in XML allows you to change it at runtime without recompiling the application, and that could come in handy if you need to change your business model with minimal downtime. Anyway, back to the markup...

From XML to TypeSpec, in 15 Lines of Code

Now that we have the XML markup, the next thing you might be wondering about is the client code: exactly how do you convert that markup into a running TypeSpec? Here's how you do it:


// Load the engine into the container
string directory = AppDomain.CurrentDomain.BaseDirectory;
SimpleContainer container = new SimpleContainer();
Loader loader = new Loader(container);
loader.LoadDirectory(directory, "*.dll");

IMxEngine engine = container.GetService();

// The instance holder will
// store the object graph once
// it's been instantiated by the engine
IInstanceHolder holder = new DefaultInstanceHolder();
string file = @"C:\YourDirectory\SimpleTypeSpecSample.xml";
engine.Execute(file, holder);

TypeSpec spec = holder.GetInstance("PersonType");
bool isPerson = spec.LooksLike();

// Use the person class normally
IPerson person = spec.CreateDuck();
person.Age = 18;
person.Name = "Me";


In the example above, I used the Simple.IOC container to instantiate the MxClone Engine. The engine, in turn, converted the XML markup into a working Person TypeSpec, and lastly, I used that same TypeSpec instance to create the IPerson instance. It's just that simple. :)

Conclusion

As you can see, there's quite a bit of development going on with LinFu.DynamicModel and LinFu.MxClone, and like everything else in the LinFu project, it will all remain under the LGPL license. I've put my heart and soul into this project, and hopefully, everyone will see that once the next set of LinFu articles comes out on CP. Stay tuned!

8 comments:

  1. Anything in the SVN yet?

    ReplyDelete
  2. Nothing yet. I'll put the new code into the SVN once I finish the article and send it out to CP.

    ReplyDelete
  3. Awesome. Can't wait to see more!

    ReplyDelete
  4. Are we there yet? :)

    ReplyDelete
  5. Not yet. :) However, I already put a copy of LinFu.MxClone and LinFu.DynamicModel in the SVN so you can play around with it in the mean time while I sort things out. Take a look, and tell me what you think. :)

    ReplyDelete
  6. very cool! I am thinking that JSON style for serialize/deserialize business objects is better that MyXaml style. Please, consider do it.
    JM

    ReplyDelete
  7. cool, can't wait to read the CP article, can anyone interested contribute in your work?

    ReplyDelete
  8. > cool, can't wait to read the CP article, can anyone interested contribute in your work?

    Absolutely. Anyone who's willing to help will always be welcome, and right now, we're in the process of creating an ORM to show off LinFu's features. If you to help us work on some really interesting projects, then just let me know on LinFu's google groups, and I'll see about getting you set up. Thanks for your interest!

    ReplyDelete

Ratings by outbrain