Click here to Skip to main content
15,867,686 members
Articles / Programming Languages / C#

Fluent Interface Pattern in C# - With Inheritance Problem

Rate me:
Please Sign up or sign in to vote.
5.00/5 (24 votes)
5 Mar 2022MIT4 min read 20.4K   145   24   16
Tutorial article on Fluent Interface Pattern in C#
This is a tutorial article that starts with an introduction to Fluent Interface Pattern in C#. This is followed by a discussion of Hierarchical Fluent Interface. Finally, quite a complicated inheritance problem with Fluent Interface Pattern is discussed. The intended audience is intermediate level C# programmers and above.

Fluent Interface Pattern – Introduction

Fluent Interface Pattern is a design guideline for OO languages that advices that exposed API, that is class public methods should, in order to increase readability, try to “appear” as a domain-specific language (DSL). Main tool to create DSL is advised to be “method chaining”. We want to have interface (API) like this:

C#
Employee empl = new Employee();
empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();

Method chaining is in C#, like in many OO languages, achieved by returning object itself, that is “this” object, as a method result. That enables next method to be chained to previous method return value. On abstract level, we are really returning a domain context to a subsequent method in method chaining. Method chaining is terminated with method that returns a void context.

Fluent Interface Pattern is just concerned about how interface should look like, it does not prescribe pattern in classical sense how to achieve it. As long as you have interface in form of method chaining, that “looks like” natural language and is therefore considered to be “user friendly”, it considers that you created your own form of “domain-specific language (DSL)” and is happy all about it.

Classic approach-Setters-Example Code

Here is a classic code example using standard setters. This kind of programming is widely advised in OO and C# literature.

C#
public class Employee
{
    private string FirstName = null;
    private string LastName = null;
    private int Age = 0;

    public void SetFirstName(string fName)
    {
        FirstName = fName;
    }

    public void SetLastName(string lName)
    {
        LastName = lName;
    }

    public void SetAge(int age)
    {
        Age = age;
    }

    public void Print()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}", 
             FirstName, LastName, Age);
        Console.WriteLine(tmp);
    }
}
class Client
{
    static void Main(string[] args)
    {
        Employee empl = new Employee();
        empl.SetFirstName("John");
        empl.SetLastName("Smith");
        empl.SetAge(30);
        empl.Print();

        Console.ReadLine();
    }
}

And here is the execution result:

FirstName:John; LastName:Smith; Age:30

Fluent Interface -Method Chaining - Example Code

Here is the code example with method chaining. This is basically the same class as in the above example, that follows recommendations of Fluent Interface Pattern. The main trick applied here is to return “this” object so methods can be chained.

C#
public class Employee
{
    private string FirstName = null;
    private string LastName = null;
    private int Age = 0;

    public Employee SetFirstName(string fName)
    {
        FirstName = fName;
        return this;
    }

    public Employee SetLastName(string lName)
    {
        LastName = lName;
        return this;
    }

    public Employee SetAge(int age)
    {
        Age = age;
        return this;
    }

    public void Print()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}", 
           FirstName, LastName, Age);
        Console.WriteLine(tmp);
    }
}

class Client
{
    static void Main(string[] args)
    {
        Employee empl = new Employee();
        empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();

        Console.ReadLine();
    }
}

And here is the execution result:

FirstName:John; LastName:Smith; Age:30

Fluent Interface -Method Chaining using Extensions-Example Code

Of course, we can use Extension methods in C# to achieve the same result as above. Please note that we needed to change access level of attributes of Employee to public, so extension methods can use them.

C#
public class Employee
{
    public string FirstName = null;
    public string LastName = null;
    public int Age = 0;
}

public static class EmployeeExtensions
{
    public static Employee SetFirstName(this Employee emp, string fName)
    {
        emp.FirstName = fName;
        return emp;
    }

    public static Employee SetLastName(this Employee emp, string lName)
    {
        emp.LastName = lName;
        return emp;
    }

    public static Employee SetAge(this Employee emp, int age)
    {
        emp.Age = age;
        return emp;
    }

    public static void Print(this Employee emp)
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}", 
          emp.FirstName, emp.LastName, emp.Age);
        Console.WriteLine(tmp);
    }
}

class Client
{
    static void Main(string[] args)
    {
        Employee empl = new Employee();
        empl.SetFirstName("John").SetLastName("Smith").SetAge(30).Print();

        Console.ReadLine();
    }
}

And here is the execution result:

FirstName:John; LastName:Smith; Age:30

Hierarchical Fluent Interface

As mentioned before, Fluent Interface pattern leaves to programmer and his judgement to decide how exactly his specific version of “domain-specific language (DSL)” is going to look like. The programmer is free to choose method names and organization of method chaining that to him looks the most “user friendly” and alike natural language.

One typical use case is creating of Hierarchical Fluent Interface. In such a case, programmer decides to group properties into hierarchical groups and in that way, expose it to the library/class user. For example, programmer might decide to divide Employee data into two groups:

  1. PersonalData; and
  2. EmploymentData

That would result in an interface like this:

C#
Employee empl = new Employee();

empl.Fluent
    .PersonalData
        .FirstName("John").LastName("Smith").Age(30)
    .EmploymentData
        .Company("CNN").Position("Host").Salary(50000);

We will provide here sample project of how to create such an interface. It is not necessarily the pattern programmer should follow to achieve Hierarchical Fluent Interface. The programmer is free to choose his own implementation technique if he desires. However, this gives a good and reusable example code. We will not be going into design/implementation details of this project, since most is self-explanatory.

Here is the class diagram:

Image 1

And here is the code for Hierarchical Fluent Interface:

C#
public class Employee
{
    //PersonalData
    public string FirstName = null;
    public string LastName = null;
    public int Age = 0;

    //EmploymentData
    public string Company = null;
    public string Position = null;
    public int Salary = 0;

    public FluentEmployee Fluent
    {
        get { return new FluentEmployee(this); }
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2} 
              \nCompany:{3}; Position:{4}; Salary:{5}",
            this.FirstName, this.LastName, this.Age, this.Company, 
            this.Position, this.Salary);
        return tmp;
    }
}

public class FluentEmployee
{
    protected Employee _employee = null;

    public FluentEmployee()
    {
        _employee = new Employee();
    }

    public FluentEmployee(Employee emp)
    {
        _employee = emp;
    }

    public FluentEmployeePersonalData PersonalData
    {
        get { return new FluentEmployeePersonalData(_employee); }
    }

    public FluentEmployeeEmploymentData EmploymentData
    {
        get { return new FluentEmployeeEmploymentData(_employee); }
    }
}

public class FluentEmployeeEmploymentData : FluentEmployee
{
    public FluentEmployeeEmploymentData(Employee emp)
        : base(emp)
    {
    }

    public FluentEmployeeEmploymentData Company(string comp)
    {
        _employee.Company = comp;
        return this;
    }

    public FluentEmployeeEmploymentData Position(string pos)
    {
        _employee.Position = pos;
        return this;
    }

    public FluentEmployeeEmploymentData Salary(int sal)
    {
        _employee.Salary = sal;
        return this;
    }
}

public class FluentEmployeePersonalData : FluentEmployee
{
    public FluentEmployeePersonalData(Employee emp)
        : base(emp)
    {
    }

    public FluentEmployeePersonalData FirstName(string fName)
    {
        _employee.FirstName = fName;
        return this;
    }

    public FluentEmployeePersonalData LastName(string lName)
    {
        _employee.LastName = lName;
        return this;
    }

    public FluentEmployeePersonalData Age(int age)
    {
        _employee.Age = age;
        return this;
    }
}

class Client
{
    static void Main(string[] args)
    {
        Employee empl = new Employee();

        empl.Fluent
            .PersonalData
                .FirstName("John").LastName("Smith").Age(30)
            .EmploymentData
                .Company("CNN").Position("Host").Salary(50000);

        Console.WriteLine(empl.ToString());
        Console.ReadLine();
    }
}

Here is the result of execution:

C#
FirstName:John; LastName:Smith; Age:30
Company:CNN; Position:Host; Salary:50000

Inheriting Fluent Interface Classes

The problem arises when we want to inherit class that implements Fluent Interface. Let us assume we have class Employee and class Manager that inherits from it. Let it be like on this class diagram:

Image 2

And here is the code:

C#
public class Employee
{
    protected string FirstName = null;
    protected string LastName = null;
    protected int Age = 0;

    public Employee SetFirstName(string fName)
    {
        FirstName = fName;
        return this;
    }

    public Employee SetLastName(string lName)
    {
        LastName = lName;
        return this;
    }

    public Employee SetAge(int age)
    {
        Age = age;
        return this;
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
            FirstName, LastName, Age);
        return tmp;
    }
}

public class Manager : Employee
{
    protected int Bonus = 0;

    public Manager SetBonus(int bonus)
    {
        Bonus = bonus;
        return this;
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3}",
            FirstName, LastName, Age, Bonus);
        return tmp;
    }
}

What we would like to have is interface like this:

C#
Manager mgr = new Manager();

mgr.SetFirstName("John").SetLastName("Smith")
    .SetAge(30).SetBonus(1000);     //will not compile

But this will not compile. The reason is that we now have two types of “this” object returned, of type Employee and of type Manager. Once we get back base class object “this” as Employee, methods of class Manager are not available any more.

So, method Employee.SetAge() would return object of type Employee and there is no way to method-chain methods from class Manager.

So, is there a way to trick method Employee.SetAge() to return object of type subclass Manager? We need that to be able to do our Fluent Interface, that is Method-Chaining?

Answer is yes, it is possible, but technically complicated. It involves usage of “Recursive Generics”. I am going to show a working code example here.

I am not going to explain in detail how the solution works. If you can read C# Generics code, you will be able to understand this quite advanced design.

Key problem that needs to be solved in this solution is how to communicate return class type from derived class to base class. Key trick is to always return in Fluent Interface object of original (derived) class. That is resolved using Generics and type parameter SELF. Follow SELF from most derived class (like CEO, Manager, Employee) down the inheritance hierarchy and you will understand how this code works. Where clause ( like “where SELF : EmployeeFluent<SELF>”) is there just to ensure that class is used as part of inheritance hierarchy.

Here is the class diagram of this solution for Inheriting Fluent Interface classes.

Image 3

Here is the code of this solution for Inheriting Fluent Interface classes.

C#
public class EmployeeFluent<SELF>
        where SELF : EmployeeFluent<SELF>
{
    protected string FirstName = null;
    protected string LastName = null;
    protected int Age = 0;

    public SELF SetFirstName(string fName)
    {
        FirstName = fName;
        return (SELF)this;
    }

    public SELF SetLastName(string lName)
    {
        LastName = lName;
        return (SELF)this;
    }

    public SELF SetAge(int age)
    {
        Age = age;
        return (SELF)this;
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}",
            FirstName, LastName, Age);
        return tmp;
    }
}

public class Employee : EmployeeFluent<Employee> { };

public class ManagerFluent<SELF> : EmployeeFluent<SELF>
        where SELF : ManagerFluent<SELF>
{
    protected int Bonus = 0;

    public SELF SetBonus(int bonus)
    {
        Bonus = bonus;
        return (SELF)this;
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3}",
            FirstName, LastName, Age, Bonus);
        return tmp;
    }
}

public class Manager : ManagerFluent<Manager> { };

public class CEOFluent<SELF> : ManagerFluent<SELF>
        where SELF : CEOFluent<SELF>
{
    protected int CompanyShares = 0;

    public SELF SetCompanyShares(int shares)
    {
        CompanyShares = shares;
        return (SELF)this;
    }

    public override string ToString()
    {
        string tmp = String.Format("FirstName:{0}; LastName:{1}; Age:{2}; Bonus:{3}; 
            CompanyShares:{4}",
            FirstName, LastName, Age, Bonus, CompanyShares);
        return tmp;
    }
}

public class CEO : CEOFluent<CEO> { };

class Client
{
    static void Main(string[] args)
    {
        CEO ceo1 = new CEO();

        ceo1.SetFirstName("John").SetLastName("Smith")
            .SetAge(30).SetBonus(1000).SetCompanyShares(5000);

        Manager mgr = new Manager();

        mgr.SetFirstName("Cedomir").SetLastName("Jokic")
            .SetAge(40).SetBonus(2000);

        Employee emp = new Employee();

        emp.SetFirstName("Novak").SetLastName("Djokovic")
            .SetAge(20);

        Console.WriteLine(ceo1.ToString());
        Console.WriteLine(mgr.ToString());
        Console.WriteLine(emp.ToString());
        Console.ReadLine();
    }
}

Here is the sample execution of this solution for Inheriting Fluent Interface classes.

Image 4

Conclusion

Fluent Interface Pattern has gained a lot of popularity and is here to stay. Just to mention LINQ where it is extensively used.

History

  • 2nd March, 2022: Initial version

License

This article, along with any associated source code and files, is licensed under The MIT License


Written By
Software Developer
Serbia Serbia
Mark Pelf is the pen name of just another Software Engineer from Belgrade, Serbia.
My Blog https://markpelf.com/

Comments and Discussions

 
QuestionQuestion Pin
Furer Alexander27-Apr-23 0:43
Furer Alexander27-Apr-23 0:43 
QuestionOne of the few gems around here Pin
joachimj17-Apr-23 22:21
joachimj17-Apr-23 22:21 
GeneralMy vote of 5 Pin
joachimj17-Apr-23 20:23
joachimj17-Apr-23 20:23 
QuestionIs there... Pin
Tomaž Štih29-Dec-22 0:18
Tomaž Štih29-Dec-22 0:18 
QuestionNice example, some suggestions Pin
Adam David Hill7-Mar-22 3:01
professionalAdam David Hill7-Mar-22 3:01 
AnswerRe: Nice example, some suggestions Pin
Mark Pelf 10-Mar-22 7:22
mvaMark Pelf 10-Mar-22 7:22 
QuestionThank you very much for this article! Pin
Rod at work4-Mar-22 4:18
Rod at work4-Mar-22 4:18 
QuestionBuilder pattern Pin
RooN3y3-Mar-22 21:33
RooN3y3-Mar-22 21:33 
GeneralMy vote of 3 Pin
Member 149289013-Mar-22 8:39
Member 149289013-Mar-22 8:39 
QuestionSeems familiar... Pin
Member 149289013-Mar-22 10:16
Member 149289013-Mar-22 10:16 
Looks like a C# version of the following Java article.

https://medium.com/@hazraarka072/fluent-builder-and-powering-it-up-with-recursive-generics-in-java-483005a85fcd[^]
QuestionInteresting but a lot of code for such a simple use case Pin
J. Frank Reeves3-Mar-22 7:46
J. Frank Reeves3-Mar-22 7:46 
QuestionNice pattern for "Fluent". Pin
Bob Gendron3-Mar-22 7:31
Bob Gendron3-Mar-22 7:31 
QuestionNice work! Pin
Tomaž Štih3-Mar-22 6:16
Tomaž Štih3-Mar-22 6:16 
GeneralMy vote of 5 Pin
Matthias Adloff3-Mar-22 4:35
professionalMatthias Adloff3-Mar-22 4:35 
QuestionExcellent! Pin
Marc Clifton2-Mar-22 11:49
mvaMarc Clifton2-Mar-22 11:49 
QuestionExciting and understandably explained Pin
Andreas Karz2-Mar-22 3:58
Andreas Karz2-Mar-22 3:58 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.