Skip to Content
Course content

65: Practice Exercise: Building a Fluent Extension Method Library

Click on the "Edit" button in the top corner of the screen to edit your slide content.

How do I actually make my extension methods "chainable"?

The secret to a fluent interface is surprisingly simple: your method must return the object it's operating on. If you're extending a class called QueryBuilder, your extension method's return type must be QueryBuilder, and the last line of your logic should almost always be return builder;.

I'll show you what I mean. Let's say we're building a simple SQL-like query generator. Instead of having a bunch of separate calls, we want to chain them together. Notice how each method takes the QueryBuilder as the this parameter and returns it right back at the end.

public static class QueryExtensions
{
    public static QueryBuilder Where(this QueryBuilder builder, string column, string value)
    {
        builder.Filters.Add($"{column} = '{value}'");
        return builder; // This is the magic line
    }

    public static QueryBuilder OrderBy(this QueryBuilder builder, string column)
    {
        builder.SortColumn = column;
        return builder;
    }
}

// Now you can do this:
var query = new QueryBuilder()
    .Where("Status", "Active")
    .Where("Role", "Admin")
    .OrderBy("CreatedAt");

Should I be modifying the original object or returning a new copy?

This is where things get interesting. It depends on whether you're working with a mutable object (like a custom class) or an immutable one (like a string). If you're extending string, you can't "modify" it—you have to return a new string. This is still "fluent," but it's a different memory pattern.

I generally recommend sticking to mutation for "Builder" patterns because it's more performant. But if you're building a data transformation pipeline, go for immutability. If I were writing a string-cleanup library for a CSV importer, it would look like this:

public static class StringCleaningExtensions
{
    public static string RemoveWhitespace(this string text) 
        => text?.Replace(" ", "") ?? string.Empty;

    public static string ToUpperCase(this string text) 
        => text?.ToUpper() ?? string.Empty;

    public static string EnsureTrailingComma(this string text) 
        => text.EndsWith(",") ? text : text + ",";
}

// Usage:
string cleanData = "  John Doe  ".RemoveWhitespace().ToUpperCase().EnsureTrailingComma();
// Result: "JOHNDOE,"

Won't these methods clutter my IntelliSense everywhere?

Yes, they will—if you put them in a generic namespace like System or your root project namespace. I've seen projects where the string type had 50+ extension methods attached to it, and it became a nightmare to find the built-in .NET methods.

The professional way to handle this is to put your fluent extensions in a dedicated namespace, something like YourProject.Extensions.Fluent. That way, the methods only appear in the autocomplete list when a developer explicitly adds using YourProject.Extensions.Fluent; at the top of their file. It keeps the global scope clean and makes it clear to other engineers that they are opting into a specific "fluent" style of coding.




📋 Practical Task

Exercise: Build a Fluent Email Message Composer

Your task is to create a fluent extension library for a simple EmailMessage class. This will allow a developer to "compose" an email using a chained syntax.

Requirements:

  • Create a class EmailMessage with properties for To, Subject, Body, and a list of Attachments.
  • Create a static class EmailExtensions containing the following extension methods:
    • SetRecipient(this EmailMessage email, string recipient)
    • SetSubject(this EmailMessage email, string subject)
    • SetBody(this EmailMessage email, string body)
    • AddAttachment(this EmailMessage email, string fileName)
  • Ensure every method returns the EmailMessage instance to allow chaining.
  • In your Main method, instantiate an EmailMessage and use a single statement (chaining) to set the recipient to "boss@company.com", the subject to "Quarterly Report", the body to "Please find it attached", and add two files: "report.pdf" and "data.xlsx".
Rating
0 0

There are no comments for now.

to be the first to leave a comment.