I. Why do we need the method chaining mechanism
First of all, please see some examples in real-world applications which are using the method chaining mechanism.
// Example 1:
var result = Employees.Where(a => e.Name == "Tim Nguyen")
.OrderBy(a => e.PhoneNumber == 0123456789)
.ToList();
// Example 2:
// The code below is to declare the main method of the .NET application in the old way.
// With .NET 6 and above, it will be different.
public class Program
{
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup()
.Build();
host.Run();
}
}
Sometimes, when you read code in some libraries or projects, you may wonder:
👉 What is the magic behind this and how can we implement it?
Actually, this way of writing code looks more natural, easier to read, and easier to extend.
II. How to implement the method chaining mechanism
1. The principle of creating the method chaining
Scenario
Without method chaining, you would normally write code like this:
var test = new TestClass();
test.Method_1();
test.Method_2();
test.Method_3();
But instead, you may want to write it like this:
var test = new TestClass()
.Method_1()
.Method_2()
.Method_3();
Solution
The principle of method chaining is:
- Each method of the class should have the return type of that class.
- The return type of the method is
this, meaning you return the current instance of the class.
Example:
// Declaration
public class TestClass
{
public int Property_1 { get; set; }
public TestClass Method_1(){
// Do something
return this;
}
public TestClass Method_2()
{
// Do something
return this;
}
}
// When we use it
var test = new TestClass()
.Method_1()
.Method_2();
👉 That’s all the magic! Quite simple, right? 😎
2. Example: JSON Builder
Let’s implement a dynamic JSON builder.
With this approach, we can create a JSON object with multiple nested levels.
Declaration
public class JsonTemplateBuilder
{
private Dictionary<object> _options = new Dictionary<object>();
public JsonTemplateBuilder Add(object key, object value)
{
_options.Add(key, value);
return this;
}
public JsonTemplateBuilder Add(string subKey, Dictionary<object> subValue)
{
_options.Add(subKey, subValue);
return this;
}
public Dictionary<object> Values()
{
return _options;
}
public string Build()
{
return JsonConvert.SerializeObject(_options);
}
}
Usage
var testJson = new JsonTemplateBuilder()
.Add("root", new JsonTemplateBuilder()
.Add("Key 1", "Value 1")
.Add(
"Key 2",
new JsonTemplateBuilder()
.Add("Key 2.1",
new JsonTemplateBuilder()
.Add("Key 2.1.1", "Value 2.1.1").Values()
)
.Add("Key 2.2",
new JsonTemplateBuilder()
.Add("Key 2.2.1", "Value 2.2.1").Values()
)
.Values()
)
.Values()
).Build();
Result
{
"root": {
"Key 1": "Value 1",
"Key 2": {
"Key 2.1": {
"Key 2.1.1": "Value 2.1.1"
},
"Key 2.2": {
"Key 2.2.1": "Value 2.2.1"
}
}
}
}
👉 And that’s how method chaining works in C#. It not only makes code cleaner but also supports builder patterns, which are super useful for JSON builders, SQL query builders, or fluent API design.