This post Fluent Interface for System.Identity – Kind’s Expression Builder got me thinking about the GoF Builder Pattern and how to turn a legacy C# class with a constructor into a Fluent Interface with a Builder and Implicit Operator.
Notice how DwellingBuilder returns a Dwelling. This is easily implemented through C#’s implicit operator. This is the Product defined by the builder pattern.
Using the Fluent Interface
Dwelling Builder
public class DwellingBuilder { int Bedrooms { get; set; } int Closets { get; set; } int Floor { get; set; } public static implicit operator Dwelling(DwellingBuilder builder) { return new Dwelling( builder.Bedrooms, builder.Closets, builder.Floor ); } public DwellingBuilder NumberOfBedrooms(int p) { Bedrooms = p; return this; } public DwellingBuilder NumberOfClosets(int p) { Closets = p; return this; } public DwellingBuilder OnFloor(int p) { Floor = p; return this; } }
Legacy Dwelling Class
public class Dwelling { public int Bedrooms { get; set; } public int Closets { get; set; } public int Floor { get; set; } public Dwelling(int bedrooms, int closets, int floor) { Bedrooms = bedrooms; Closets = closets; Floor = Floor; } }


{ 7 comments… read them below or add one }
In general, I would comment that implicit operators are hard for your average developer to use/discover. To me, this makes the code less readable and more difficult to use.
One example is XName and string in LINQ; developers that encounter this for the first time are easily confused.
It would perhaps be easier to use DwellingBuilder with a static method that returned an instance of DwellingBuilder (DwellingBuilder would have a private constructor) and an instance Create() method which returned a Dwelling.
The call would then look like:
Dwelling dwelling = DwellingBuilder.New.NumberOfBedRooms(1).NumberOfClosets(2).OnFloor(3).Create();
The intellisense would clearly show that the the Create() method would yield a return of type Dwelling.
I do like the use of the implicit operator for this kind of thing.
However, I don’t like the application of fluid interface in this particular case.
The Dwelling requires all 3 parameters, but the fuild interface does not communicate this. It looks like Dwelling dwelling = new DwellingBuilder().NumberOfBedRooms(1); is a valid usage, but it is not.
It would have been more applicable in case of default constructor and settable properties. But class initializers are applicable in the later case.
@Sergey while the constructor of Dwelling requires 3 parameters your example is ‘valid’. Both Closets and Floor are set to zero and a fully realized object is returned.
@Charles I understand. Adding New and Create do give hints but require specific ordering in the fluent interface which lead to other issues.
Doug,
The core parts of it are still interchangeable (rooms, closets, floor) and thus the impact is minimal. You have to call a Create() method at the end, but syntactically, it is more readable.
As soon as you start programming for yourself, you forget that you’re writing code that is usually going to be used, maintained, and fixed by others. This is a terrible mistake to make, especially if you’re a consultant. Being able to write slick code is of lesser importance than being able to write usable code. The two intersect from time to time, but in this case, the intellisense hints far outweigh any benefits from the use of the implicit operator.
My guess is that a sizable percentage of .NET developers don’t know what an implicit operator is and don’t know how to write one. They might be able to use it, but it wouldn’t be intuitive.
@Doug, while in this example you can get away with default values.
In real life, a dwelling with 0 floors or rooms is not a valid object. Which means you’d need to be able to modify those properties later. And if I was designing a dwelling as a mutable class I’d just provide a default constructor and settable properties.
On the other hand, if I requested those parameters in the constructor it would be because I made the dwelling immutable. And in that case I’d require valid values provided in the constructor.
It could be
var d = new Dwelling()
{
Bedrooms = 3,
Closets = 2,
Floor = 23
};
but still Thank You for the idea!!!
Now I will use ‘builders’ for many of my objects, where more complex construction logic is required.