Open Sam13 opened 3 months ago
Hi @Sam13,
Thank you for this!
What you want to achieve is already possible like so:
[FluentApi]
public class Student
{
[FluentMember(0)]
public string FirstName { get; private set; }
[FluentMember(1)]
public string LastName { get; private set; }
[FluentMember(2)]
[FluentContinueWith(2)]
public string? FavoriteFood { get; private set; }
[FluentMember(2)]
[FluentContinueWith(2)]
public string? Hobby { get; private set; }
[FluentMethod(2)]
public void Create()
{
}
}
A final method, called Create
in this example, is needed in the last step to conclude the setting of the optional properties:
Student alice1 = CreateStudent
.WithFirstName("Alice")
.WithLastName("TestName")
.WithHobby("Reading")
.WithFavoriteFood("Pizza")
.Create();
Admittedly, the attributes that have to be specified for this group of optional properties are not very intuitive. Maybe we can come up with a better syntax for this.
Happy coding! Kevin
Hi @m31coding
Those methods are still part of the builder, aren't they? What I would prefer are ordinary extension methods on the original type. This does not need a dummy final method.
As example the method of my first post
public static Student WithHobby(this Student student, string hobby)
{
student.Hobby = hobby; // Probably set via reflection
return student;
}
What do you think?
Ah, now I understand your approach. As you pointed out, no dummy final method would be needed. However, the downside is that the extension method remains available after the instance is constructed, which undermines the immutability of the Student
class.
I lean towards bundling the methods for building the instance within the builder class. I agree that the final dummy method is not ideal. Another way to avoid it could be using an implicit conversion operator. For this to work, the fluent API would need to expose a class instance (rather than an interface) in the final step, allowing for the setting of optional properties and the implicit conversion to a Student
instance.
Ah, now I understand your approach. As you pointed out, no dummy final method would be needed. However, the downside is that the extension method remains available after the instance is constructed, which undermines the immutability of the
Student
class.
That's exactly what I want - the extension methods should be available after construction. This allows creating an instance which can be customized later on - even in code outside of my control... With the builder you create the instance with the mandatory properties and with the extension you can customize the optional properties.
If you want immutable data structures you may use C# records?
Assuming Student
is a record the extension methods would look like that:
public static Student WithHobby(this Student student, string hobby)
{
return student with { Hobby = hobby };
}
What about generating additional extension methods for optional properties which can be populated in any order after fluent builder was fully executed?
Example:
Usage:
Generated code (pseudo code):