UsageBuilder

Jay Tuley edited this page May 2, 2013 · 2 revisions

Introduction

If you are familiar with the Clay Project they have a ClayFactory that uses a really cool inline syntax to initialize a prototype clay object.

      dynamic New = new ClayFactory();

      var person = New.Person(
          FirstName: "George",
          LastName: "Washington"
      );

But a clay object uses a lot of Inversion of Control— you can change it's behavior entirely by plugging in different behaviors,but this flexibility comes with a cost that you may not need to be paying for just a plain old prototype object.

#Typical ImpromptuBuilder #

if you included ImpromptuInterface.Dynamic you can do the same thing

      dynamic New = Builder.New();

      var person = New.Person(
          FirstName: "George",
          LastName: "Washington"
      );

And this runs about 100x faster at accessing properties than the clay object and supports 99% of what a ClayFactory creates.

But there's more flexibility then just that. The ImpromptuBuilder can actually initialize any object including ExpandoObject

      dynamic New = Builder.New<ExpandoObject>();

      var person = New.Person(
          FirstName: "George",
          LastName: "Washington"
      );

.NET 4.0's built in ExpandoObject runs about 5x faster than ImpromptuBuilder's default (ImpromptuDictionary) obviously it won't do everything the clay factory's prototype did but since ExpandoObject runs 500x faster than the clay result you probably want to make sure you really needed the extra functionality.

Since ImpromptuBuilder can work with any object it even can produce the same result as the ClayFactory.

 var New = Builder.New<Clay>()
                  .ObjectSetup(
                   Return<object[]>.Arguments(
                  () => new object[]{
                    new InterfaceProxyBehavior(),
                    new PropBehavior(),   
                    new ArrayPropAssignmentBehavior(),
                    new NilResultBehavior()}))
                  .ArraySetup(
                  Return<object[]>.Arguments(
                  ()=>new object[]{
                    new InterfaceProxyBehavior(),
                    new PropBehavior(),
                    new ArrayPropAssignmentBehavior(),
                    new ArrayBehavior(),
                    new NilResultBehavior()}));

  var directory = New.Array(
                        New.Person().Name("Louis").Aliases(new[] { "Lou" }),
                        New.Person().Name("Bertrand").Aliases("bleroy", "boudin")
                        ).Name("Orchard folks");

Not pretty but you can encapsulate the creation of the New variable and it makes it easy to switch between what prototype object you need.

One of the features the ClayFactory's result has is an InterfaceProxyBehavior which creates interface proxies for the clay object. Creating Interface proxies is the main feature of ImpromptuInterface (see [UsageBasic]). However, there are slight difference between the two, a Clay object can be cast to an Interface and it will just automatically be wrapped, this can be useful, and Impromtu's has to be explicitly called using ActLike<Interface>() this can be safer you have to consciously decide to use it. Because of these difference you can actually use Impromptu's proxies with a clay object interchangeable. Impromptu's proxies don't use DynamicProxy like clay, and while DynamicProxy is pretty efficient, Impromptu's run about 10% faster on creation and 30% faster on invocation when wrapping a Clay object.

#Simplified ImpromptuBuilder #

The above Builder.New<Type> syntax to create the builder has a lot of flexibility but you have to create it first before you can use the constructing method. If you want a quicker simplified inline syntax and don't need configuration than you can use Build<Type>.NewObject instead.

#Advanced ImpromptuBuilder#

The builder can actually setup multiple kinds of builders based on name.


      dynamic New = Builder.New().Setup(
                                    Expando: new Activate<ExpandoObject>(),
                                    Clay: new Activate<Clay>( () => new object[]{
                                                     new InterfaceProxyBehavior(),
                                                     new PropBehavior(),   
                                                     new ArrayPropAssignmentBehavior(),
                                                     new NilResultBehavior()});

     var expandoPerson = New.Expando(
          FirstName: "George",
          LastName: "Washington"
      );       

      var clayPerson = New.Clay(
          FirstName: "George",
          LastName: "Washington"
      );
 
      //Unsetup names uses the 'Object' builder which if not set is an `ImpromptuDictionary`
      var defaultPerson = New.Unknown(
          FirstName: "George",
          LastName: "Washington"
      );

#Inline Lambda#

If you need to inline a lamba you can always do new Func<T>(lambda) or new Action<T>(lambda). ImpromptuInterface has an alternative form that can be used interchangeably.


var tRegularSyntax = new Func<int,string>(i=>"index: "+i);

var tImpromptuSyntax = Return<string>.Arguments<int>(i=>"index: "+i);

var tRegularSyntax = new Action<string>(hello=>Console.WriteLine(hello));

var tImpromptuSyntax = ReturnVoid.Arguments<string>(hello=>Console.WriteLine(hello));

Either work and can be a property on a builder.

     var person = New.Test(
          One: 1,
          Two: 2
          OnePlus: Return<int>.Arguments<int>(x=>x+1)
      );

     var tResult = person.OnePlus(2);