Fluent Silverlight – Implementing a fluent API

Introduction

Quite some time has passed since we published our Fluent Silverlight framework. In the mean time we have been very busy extending the framework and using it in our internal products. Unfortunately we have been so busy that there was no time left to publish the extension we made.

Never the less there has been some interest in this framework lately such as that I decided to finally take a spin an bring the current version that we use internally in our company to a level where I can publish it. The updated framework will be published shortly.

Since code alone does not always show the possibilities how to use it I want to second it with a series of short articles.

A fluent API

A good description on what a fluent API is can be found here. Generally spoken a fluent API makes the code more readable.

In our context we can identify four different categories that we want to define via the fluent interface.

Let me show a simple sample of a fluent API which incorporates the first two categories mentioned above.

Car car = new CarExpression()

.Make("Kia Sorento")

.ListPrice(22500)

.Type.SUV()

.Build();

First I create an instance of type CarExpression. Then I define the make and list price of the car which are standard properties of type string and decimal respectively. Next I define the type of the car which is an enum. Finally I tell the CarExpression to build the car with the given settings. The definition of the Car class is just

publicclass Car

{

publicstring Make { get; set; }

publicdecimal ListPrice { get; set; }

public CarTypes Type { get; set; }

}

and the CarTypes enum is defined as follows

publicenum CarTypes

{

SportsCar, SUV, MiniVan, Sedan

}

having defined these two types I can then start implementing the CarExpression as shown below

publicclass CarExpression

{

privatestring make;

privatedecimal listPrice;

private CarTypes carType;

public CarExpression Make(stringvalue)

{

make = value;

returnthis;

}

public CarExpression ListPrice(decimalvalue)

{

listPrice = value;

returnthis;

}

}

We can see that for each property of the car that I want to define via the fluent API I have defined an internal field in the CarExpression. For normal properties like Make the definition of the corresponding method in the fluent API is simple. It’s always a method which returns an object of type CarExpression. Thus we will always have a return this; statement at the end of the method. Other than that the method just stores the passed in parameter value in the corresponding internal field for future use.

It is the fact that the methods are always returning “this” makes it possible to have a fluent interface.

Enum type properties are a little bit more involved. We have to implement an expression on its own for each enum we want to use in our fluent API. Let me show the code used for the CarTypes enum

The points to mention are that the expression is generic. The generic parameter TParent will correspond to the expression in which context this enum expression is going to be used. In our simple sample this will be the CarExpression. The other point to mention is the constructor. The constructor expects 2 parameters, the first being the parent expression inside which this enum expression is used and the second parameter is the action that shall be executed by this enum expression whenever one of its methods is used. The enum expression is only a helper expression and thus must not store any values internally but rather pass selected values back to the parent expression. That is the reason why we have to define this action.

Now let’s have a look a one of those methods of the enum expression. In the first line we use the action mentioned above and pass as a parameter the correct enum value. Then we return the parent expression instance. This is very important! We want to continue working with the car expression once we have selected a car type. If we would instead return “this” then we could only select other types which makes absolutely no sense…

The reason why we have chosen the enum expression to be generic in TParent is that we might want to use an enum expression in different contexts, that is inside different parent expressions. If we are 100% sure that we are only going to use an enum expression inside a single type of expression then we could simplify the above enum expression and make it non-generic.

As you will notice we have implemented the Type as a readonly property and not as a method. Please also note the lamda expression which defines the action we pass to the enum expression

x => carType = x

This lambda expression tells the system to take the parameter that the respective method in the enum expression will pass to the action and assign its value to the field carType of the car expression.

What I do not like in my fluent API that I have defined so far is the fact that I have to call a Build method to tell the expression to build an instance of a car. That seems something unnecessary to me… How can I let the expression know that I want to have my car built without explicitly telling it? Well if I don’t want to tell it explicitly then I have to tell it implicitly. What means do I have to tell something implicitly? Oh yes, i can use operator overloading to define an implicit type cast operation.

Whenever I assign an object of type CarExpression to a variable of type Car the system tries to do an implicit type conversion. If no such conversion is defined the system will throw a TypeCastException. But we can define such an implicit type conversion. In our sample the code needed looks like this

publicstaticimplicitoperator Car(CarExpression expression)

{

returnnew Car

{

Make = expression.make,

ListPrice = expression.listPrice,

Type = expression.carType

};

}

We can now update our usage of the expression like shown below

Car car = new CarExpression()

.Make("Kia Sorento")

.ListPrice(22500)

.Type.SUV();

This is much more natural than explicitly calling some Build method.

About Gabriel Schenker

Gabriel N. Schenker started his career as a physicist. Following his passion and interest in stars and the universe he chose to write his Ph.D. thesis in astrophysics. Soon after this he dedicated all his time to his second passion, writing and architecting software. Gabriel has since been working for over 25 years as a consultant, software architect, trainer, and mentor mainly on the .NET platform. He is currently working as senior software architect at Alien Vault in Austin, Texas. Gabriel is passionate about software development and tries to make the life of developers easier by providing guidelines and frameworks to reduce friction in the software development process.
Gabriel is married and father of four children and during his spare time likes hiking in the mountains, cooking and reading.

The CarTypeExpression stuff is quite clever, but unfortunately violates the DRY principle – how about implementing a WithType method on CarExpression as opposed to hard-coding types in the CarTypeExpression class?

@Eric: the idea of the whole fluent API is to maximaize readability and understandability. In my opinion it is justified to trade in DRY for this. It’s similar to the case when you are writing unit tests or any test. There also the clarity and expressiveness of a test is more important than then DRY principle.