When working in applications you might often find that the source code has become so complex that it is difficult to understand and maintain. Fluent interfaces and method chaining are two concepts that attempt to make your code readable and simple. This article examines fluent interfaces and method chaining and how you can work with them in C#.
To work with the code examples provided in this article, you should have Visual Studio 2019 installed in your system. If you don’t already have a copy, you can download Visual Studio 2019 here.
Create a console application project in Visual Studio
First off, let’s create a .NET Core console application project in Visual Studio. Assuming Visual Studio 2019 is installed in your system, follow the steps outlined below to create a new .NET Core console application project in Visual Studio.
- Launch the Visual Studio IDE.
- Click on “Create new project.”
- In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
- Click Next.
- In the “Configure your new project” window, specify the name and location for the new project.
- Click Create.
This will create a new .NET Core console application project in Visual Studio 2019. We’ll use this project in the subsequent sections of this article.
Fluent interfaces and method chaining explained
Method chaining is a technique in which methods are called on a sequence to form a chain and each of these methods return an instance of a class. These methods can then be chained together so that they form a single statement. A fluent interface is an object-oriented API that depends largely on method chaining. The goal of a fluent interface is to reduce code complexity, make the code readable, and create a domain specific language (DSL). It is a type of method chaining in which the context is maintained using a chain.
You might already be using method chaining in your applications, knowingly or unknowingly. The following code snippet illustrates how methods are chained.
var data = authorList.Where(a => a.Country == "USA")
.OrderBy(a => a.AuthodId)
.ToList();
In method chaining, when you call a method the context flows from the method called to another method, i.e., the next method in the chain. Hence the term “chaining” is used to describe this pattern.
Method chaining example in C#
The following code snippet provides a good example of method chaining.
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.Build();
host.Run();
}
}
Fluent interfaces vs. method chaining
While there are similarities between fluent interfaces and method chaining, there are also subtle differences between the two. Whereas fluid interfaces typically act on the same set of data, method chaining is used to change the aspects of a more complex object.
In a fluent interface, the methods should return an instance of the same type. In method chaining, the methods may return instances of any class. It should also be noted that fluent interfaces are implemented using method chaining, but not all uses of method chaining are fluent interfaces. While method chaining usually works on a simple set of data, fluent interfaces are usually used to modify a complex object.
Create an OrderBL class without method chaining in C#
Select the console application project we created above in the Solution Explorer window and create a new class called OrderBL. Now, enter the following code in the new class.
public class OrderBL
{
public Guid OrderId { get; set; }
public int OrderType { get; set; }
public DateTime OrderDate { get; set; }
//Other properties relevant to the Order class goes here
public OrderBL InitializeOrder(Guid OrderId)
{
if (OrderId == Guid.Empty)
OrderId = Guid.NewGuid();
else
this.OrderId = OrderId;
OrderType = 2;
OrderDate = DateTime.Now;
return this;
}
public void ValidateOrder(Guid OrderId)
{
//Write your code to validate the order here
}
public void SearchOrder(Guid OrderId)
{
//Write your code here to search an order in the database.
}
public void ProcessOrder()
{
//Write your code here to process an order.
}
public void CancelOrder(Guid OrderId)
{
//Write your code here to cancel an order.
}
public void SaveOrder()
{
//Write your code here to save order information in the db.
}
}
You can now invoke the methods of the OrderBL class in a sequence in the Main method of the Program class as shown in the code snippet given below.
static void Main(string[] args)
{
Guid OrderId = Guid.Parse("9043f30c-446f-421f-af70-234fe8f57c0d");
OrderBL orderBL = new OrderBL();
orderBL.InitializeOrder(OrderId);
orderBL.ValidateOrder(OrderId);
orderBL.ProcessOrder();
orderBL.SaveOrder();
Console.ReadKey();
}
Create an OrderBL class with method chaining in C#
To implement method chaining, you should return an instance from the methods you want to be in the chain. In the OrderBL example above, the methods have been called in a sequence but you’ve had to write multiple lines of code — one for each method call. So, to take advantage of method chaining here, you should change the return type of the methods to a class name such as OrderBL. You should also return an instance of a class (not necessarily OrderBL) from the methods you want to participate in the chain.
For the sake of simplicity let’s assume that the return type of the participating methods is OrderBL. You should now specify return this;
from these participating methods. The updated version of the OrderBL class is given below.
public class OrderBL
{
Guid OrderId { get; set; }
int OrderType { get; set; }
DateTime OrderDate { get; set; }
//Other properties relevant to the Order class goes here
public OrderBL InitializeOrder(Guid OrderId)
{
if (OrderId == Guid.Empty)
OrderId = Guid.NewGuid();
else
this.OrderId = OrderId;
OrderType = 2;
OrderDate = DateTime.Now;
return this;
}
public OrderBL ValidateOrder(Guid OrderId)
{
return this;
//Write your code to validate the order here
}
public OrderBL SearchOrder(Guid OrderId)
{
return this;
//Write your code here to search an order in the database.
}
public OrderBL ProcessOrder()
{
return this;
//Write your code here to process an order.
}
public void CancelOrder(Guid OrderId)
{
//Write your code here to cancel an order.
}
public void SaveOrder()
{
//Write your code here to save order information in the db.
}
}
You can now call the methods in a chain as illustrated in the code snippet given below.
static void Main(string[] args)
{
Guid OrderId = Guid.Parse("9043f30c-446f-421f-af70-234fe8f57c0d");
OrderBL orderBL = new OrderBL();
orderBL.InitializeOrder(OrderId).ValidateOrder(OrderId).
ProcessOrder().SaveOrder();
Console.ReadKey();
}
Note that because the return type of Save is void, the method chain shown in the preceding code snippet ends there.
You might want to use fluent interfaces and method chaining when you want your code to be simple and readable by non-developers. The goal of fluent interfaces is to make the code simple, readable, and maintainable. You can implement fluent interfaces in C# using method chaining, factory classes, and named parameters. I’ll have more to say about fluent interfaces and method chaining in a future post here.
How to do more in C#:
- How to unit test static methods in C#
- How to refactor God objects in C#
- How to use ValueTask in C#
- How to use immutability in C
- How to use const, readonly, and static in C#
- How to use data annotations in C#
- How to work with GUIDs in C# 8
- When to use an abstract class vs. interface in C#
- How to work with AutoMapper in C#
- How to use lambda expressions in C#
- How to work with Action, Func, and Predicate delegates in C#
- How to work with delegates in C#
- How to implement a simple logger in C#
- How to work with attributes in C#
- How to work with log4net in C#
- How to implement the repository design pattern in C#
- How to work with reflection in C#
- How to work with filesystemwatcher in C#
- How to perform lazy initialization in C#
- How to work with MSMQ in C#
- How to work with extension methods in C#
- How to us lambda expressions in C#
- When to use the volatile keyword in C#
- How to use the yield keyword in C#
- How to implement polymorphism in C#
- How to build your own task scheduler in C#
- How to work with RabbitMQ in C#
- How to work with a tuple in C#
- Exploring virtual and abstract methods in C#
- How to use the Dapper ORM in C#
- How to use the flyweight design pattern in C#