To improve the usability of the Fluent API for nested properties, I propose introducing a lambda method for building nested objects. Consider the following classes:
public class Student
{
public string Name { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string Street { get; set; }
public string HouseNumber { get; set; }
}
To achieve this, I would like to introduce a new attribute FluentLambda, to be used instead of FluentMember for properties that have their own Fluent API. The Fluent API classes will look like this:
[FluentApi]
public class Student
{
[FluentMember(0)]
public string Name { get; set; }
[FluentLambda(1)]
public Address Address { get; set; }
}
[FluentApi]
public class Address
{
[FluentMember(0)]
public string Street { get; set; }
[FluentMember(1)]
public string HouseNumber { get; set; }
}
Create an object for the initial step
In order to realize the described feature, an object is required that exposes the methods of the first, initial step. Currently, this object can not be obtained, since the first step is static:
For the first step the CreateStudent builder must implement two methods, a static method and a non-static method:
public static IWithAddress WithName(string name)
{
CreateStudent createStudent = new CreateStudent();
createStudent.student.Name = name;
return createStudent;
}
public IWithAddress WithName(string name)
{
student.Name = name;
return this;
}
Unfortunately, these methods collide because they have the same signature. Luckily, this can be fixed by changing all interface implementations of the builder to explicit interface implementations. With this approach, the second method has a different signature and becomes:
The difference between a normal interface implementation and an explicit interface implementation is that for the latter, the method can only be called through the interface. For example, if you have an object SomeObject someObject, you cannot call the explicitly implemented interface method directly on someObject. However, if the variable type corresponds to the interface, such as ISomeInterface someObject, then you can call the explicitly implemented interface method.
The change to explicit interface implementations is a non-breaking change for the Fluent API library because it exposes interfaces rather than builder class objects.
Overview
To improve the usability of the Fluent API for nested properties, I propose introducing a lambda method for building nested objects. Consider the following classes:
We want to enable the following API usage:
To achieve this, I would like to introduce a new attribute
FluentLambda
, to be used instead ofFluentMember
for properties that have their own Fluent API. The Fluent API classes will look like this:Create an object for the initial step
In order to realize the described feature, an object is required that exposes the methods of the first, initial step. Currently, this object can not be obtained, since the first step is static:
The corresponding builder method is:
I propose the implementation of a method
InitialStep
that returns an interfaceICreateStudent
:where
With these additions, the
WithAddress
method can be implemented with theCreateAddress.InitialStep
method as follows:Explicit interface implementations
For the first step the
CreateStudent
builder must implement two methods, a static method and a non-static method:Unfortunately, these methods collide because they have the same signature. Luckily, this can be fixed by changing all interface implementations of the builder to explicit interface implementations. With this approach, the second method has a different signature and becomes:
The difference between a normal interface implementation and an explicit interface implementation is that for the latter, the method can only be called through the interface. For example, if you have an object
SomeObject someObject
, you cannot call the explicitly implemented interface method directly onsomeObject
. However, if the variable type corresponds to the interface, such asISomeInterface someObject
, then you can call the explicitly implemented interface method.The change to explicit interface implementations is a non-breaking change for the Fluent API library because it exposes interfaces rather than builder class objects.