Builder pattern in C# with nested objects

I’ve used the builder pattern a lot recently for writing unit test setups, filling data into in-memory database. It can be used with nice fluent syntax too.

var document = new DocumentBuilder()
  .WithName("My document")
  .WithIcon("mydoc.png")
  .Build();

But what I’ve been trying to figure out, what’s the preferred way to do nested objects (or parent-child-relationships). Let’s say that I’m trying to build a document folder tree. I have folders, inside folders I have documents and sub-folders.

Most common syntax I’ve seen is chaining:

var documentTree = new DocumentTreeBuilder()
  .AddFolder()
    .WithName("Root folder")
    .WithIcon("myfolder.png")
    .AddFile()
      .WithName("My document")

But how do you return to parent builder? Maybe with Build commands?

var documentTree = new DocumentTreeBuilder()
  .AddFolder()
    .WithName("Root folder")
    .WithIcon("myfolder.png")
    .AddFile()
      .WithName("My document")
      .Build()
    .Build()
  .Build();

Well that works, but it has two issues. The unnecessary Build commands can get annoying, especially if you have lots of children that don’t need customization (what if I have 10 “AddFiles”?). Plus the child builder always needs to have a reference to parent builder, which gets more complicated if the child can have multiple different types of parents (which is quite common in my case at least). Then you’ll need to have generic type parameter for the child builder, just to get the parent builder.

public class ParentBuilder1 {
  public ChildBuilder<ParentBuilder1> AddChild() { ... }
}
public class ParentBuilder2 {
  public ChildBuilder<ParentBuilder2> AddChild() { ... }
}
public class ChildBuilder<TParent> {
  public TParent Build() { ... }
}

No, there has to be a better way. Someone on Stackoverflow also suggested using the XDocument building syntax.

var docTree = new DocumentTree(
  new Folder("Root folder",
    new Icon("myfolder.png")
    new Document("My document")
  )
);

But this has the big issue that children, including parameters that you don’t want to specify in constructor, need to be provided in untyped array, which makes it very error-prone.

Eventually I decided to settle on using callbacks.

var docTree = new DocumentTreeBuilder()
  .AddFolder("Root folder", folder => folder
    .WithIcon("myfolder.png")
    .AddDocument("My document")
  )
  .Build();

What I like about this is that the child builder doesn’t need to know about the parent, and it’s always clear when you’re building the child vs. parent.

Objects can be “exported” with C# “out” parameters.

.AddFolder("Root folder", folder => folder
  .AddDocument("My document")
  , out var folder);

Although, if you want to export from child builders you’ll need to declare the variables before the builder. Also too bad C# doesn’t allow default values for out parameters.

I made a GitHub repo that hopefully demonstrates the end result better.

Leave a Reply