How to write fluent interface with C# and Lambda.

Last week I had a nice discussion in the office about “how to write fluent interface” and I have found a couple of articles over the internet about that. As usual I disagree with some of them and, as usual, my friend Mauro Servienti (MVP C#) has a nice article about it, unfortunately in Italian. He just gave me the startup input.

If you think about the Fluent Interface, it is just a trick that you use with C# in order to cheat the intellisense of Visual Studio and in order to create a nice style for your code. Of course there is a specific way to write fluent interface.

Let’s make a short sample. The classic Person class and the factory pattern.

We have a class which represents the Person Entity and has some common properties.

Very easy. Now, in a normal world you would have something like this, in order to create a new instance of a class person.

First of all, here we have a big problem. All the parameters are strings. So, if we don’t explain in a proper verbose way each parameter, the developer that will use our factory won’t be able to know what to write in each parameter. Second thing, if we don’t use C# 4 we have to specify each parameter value anyway … Finally we are avoiding a nice readability in our code.

The first step for a fluent interface.

I saw a lot of code around the web but a lot of people forget about the name of this technique … The name is Fluent Interface so this means that probably we should add some interfaces in our code in order to have a good result. Well VS 2010 is able to create an interface from a class just with a couple of clicks … And this is the final result:

Now we need to translate each method in a Fluent method. Let’s start with the class person. What I am doing is an interface for my Factory and two methods, one for the Factory initialization, where we initialize a new instance of the class person and one to finalize it, where we will return the current instance of that class. Of course we need also the methods to add some values to the person properties. Look at the UML:

At here is the code:

IPersonFactory

publicinterfaceIPersonFactory

{

IPersonFactory Initialize();

IPersonFactory AddFirstName(string firstName);

IPersonFactory AddLastName(string lastName);

IPersonFactory AddMiddleName(string middleName);

IPerson Create();

}

And this is the implementation:

PersonFactory

publicclassPersonFactory : IPersonFactory

{

privateIPerson person = null;

publicIPersonFactory Initialize()

{

person = newPerson();

returnthis;

}

publicIPersonFactory AddFirstName(string firstName)

{

person.FirstName = firstName;

returnthis;

}

publicIPersonFactory AddLastName(string lastName)

{

person.LastName = lastName;

returnthis;

}

publicIPersonFactory AddMiddleName(string middleName)

{

person.MiddleName = middleName;

returnthis;

}

publicIPerson Create()

{

return person;

}

}

So now we start to have a FluentInterface capability in our code.

Code Snippet

var person = newPersonFactory()

.Initialize()

.AddFirstName(“Raffaele”)

// we can skip this line now …

.AddMiddleName(string.Empty)

.AddLastName(“Garofalo”)

.Create();

Very well done but we still have a problem here. We are not giving a constraint to the developer that will use our fluent syntax. Let’s say that we are working with a retarded colleague, nobody can prohibit him to write something like this:

Wrong Person

var wrongPerson = newPersonFactory().Create();

In this case he will get a nice NullReferenceException because if he doesn’t call the method Initialize the factory won’t create a new instance of the class person … So how can we add a constraint to our interface? Very simple, we need 3 interfaces and not only one anymore. We need IInitFactory, IPersonFactory and ICreateFactory.

Let’s see the code:

IPersonFactory

publicinterfaceIPersonFactory

{

IPersonFactory AddFirstName(string firstName);

IPersonFactory AddLastName(string lastName);

IPersonFactory AddMiddleName(string middleName);

IPerson Create();

}

The IPersonFactory now will not be in charge anymore of creating a new instance of the class person, it will just be in charge of working with it. We will use dependency injection to inject a new instance. Let’s the concrete implementation of this factory:

Person Factory refactored

publicclassPersonFactory : IPersonFactory

{

privateIPerson person = null;

public PersonFactory(IPerson person)

{

this.person = person;

}

publicIPersonFactory AddFirstName(string firstName)

{

this.person.FirstName = firstName;

returnthis;

}

publicIPersonFactory AddLastName(string lastName)

{

this.person.LastName = lastName;

returnthis;

}

publicIPersonFactory AddMiddleName(string middleName)

{

this.person.MiddleName = middleName;

returnthis;

}

publicIPerson Create()

{

returnthis.person;

}

}

Now we need an orchestrator. Somebody that will be visible outside and will be in charge of giving to the fluent syntax a static flavor (we want to avoid the new Factory() syntax …) and that will return a PersonFactory ready to work …

Person Fluent Factory

publicstaticclassPersonFluentFactory

{

publicstaticIPersonFactory Init()

{

returnnewPersonFactory(newPerson());

}

}

And now Visual Studio will follow our rules …

Final Step, Lamba expression for a cool syntax.

Ok this is cool and it works like we want but … it is really time consuming. We want a fluent interface and that’s fine but if you a domain with 100 entities and more or less 100 factories, can you imagine the pain in the neck in order to adopt this pattern all over?? Well this is the reason you should study more in depth C#!! If you didn’t know, there is a cool syntax future in C# called Lambda Expressions. If you don’t know what I am talking about, have a look here.

First of all we need a generic interface for our factory with only two methods, one to add a value to a property and one to return the current instance of the entity created by the factory.

Disclaimer

All content provided on this blog is for informational purposes only. The owner of this blog makes no representations as to the accuracy or completeness of any information on this site or found by following any link on this site.

Advise for SpammersThis blog is manually moderated, please stop to post scam, spam and other annoying comments as they will never get approved, thank you.

Support MeDid you enjoy the content of this blog, then just click the banner below, it will give me back some money which I will use to keep running this blog.