DEV Community

Cover image for Expression Bodied Collection Property Initialization Gotcha in C#
Sung M. Kim
Sung M. Kim

Posted on • Originally published at slightedgecoder.com on

2 1

Expression Bodied Collection Property Initialization Gotcha in C#

This is a post from 2017 but as I was re-learning Trie I read it over and made it available here 🙂

I was implementing a trie, which is a tree data structure, usually for storing strings for searching. Since it’s a tree, it has a “Children” for holding child nodes.

But then I ran into a problem where simply calls to adding children to a collection (Line# 9) didn’t work.

private void Insert(TrieNode current, string word)
{
foreach (char c in word)
{
current.Children.TryGetValue(c, out TrieNode node);
if (node == null)
{
node = new TrieNode();
current.Children.Add(c, node);
}
current = node;
}
current.IsCompleteWord = true;
}
view raw insert.cs hosted with ❤ by GitHub

After 30 minutes of debugging, I was like…

cat banging head on the table

Just what the h**l happened?

TL;DR

Auto Property initialization creates a backing field while Expression Bodied property one does not

▬ Introduction ▬

According to Wikpedia, you can declare a trie like this (in Haskell).

import Data.Map
data Trie a = Trie { value :: Maybe a,
children :: Map Char (Trie a) }
view raw Trie.hs hosted with ❤ by GitHub

So I created a TrieNode class as shown below.

public class TrieNode
{
public bool IsCompleteWord { get; set; } = false;
public Dictionary<char, TrieNode> Children => new Dictionary<char, TrieNode>();
}
view raw TrieNode.cs hosted with ❤ by GitHub

*If you are an astute reader, you might have already spotted the problem. Congratulations!*

▬ Problem ▬

The complete source for building a trie, TrieBuilder is declared as below.

public class TrieBuilder
{
public TrieNode BuildTrie(IEnumerable<string> words)
{
TrieNode root = new TrieNode();
foreach (var word in words)
{
Insert(root, word);
}
return root;
}
private void Insert(TrieNode current, string word)
{
foreach (char c in word)
{
current.Children.TryGetValue(c, out TrieNode node);
if (node == null)
{
node = new TrieNode();
current.Children.Add(c, node);
}
current = node;
}
current.IsCompleteWord = true;
}
}
view raw TrieBuilder.cs hosted with ❤ by GitHub

Given a list of words passed to BuildTrie method, it populates a trie and returns an object instance.

Insert method simply checks for an existence of a character and maps current character to a node to the trie object instance , current.

This is where the problem occurred. current.Children.Add(...) wasn’t adding node object instance.

▬ Investigation ▬

Later on, I found out a StackOverflow answer explanating that declaring a property with => syntax (introduced in C# 6) does NOT create a backing field.

So my declaration below,

public Dictionary<char, TrieNode> Children => new Dictionary<char, TrieNode>();
view raw Children1.cs hosted with ❤ by GitHub

is equivalent to

public Dictionary<char, TrieNode> Children
{
get { return new Dictionary<char, TrieNode>(); }
}
view raw Children2.cs hosted with ❤ by GitHub

returning a new array whenever Children property was accessed, thus not adding a new node to it.

▬ Solution ▬

The fix is simple. Declare Children with a backing field or use an auto property initialization syntax.

public Dictionary<char, TrieNode> Children { get; } = new Dictionary<char, TrieNode>();
view raw Children3.cs hosted with ❤ by GitHub

Above declaration is equivalent to

private readonly Dictionary<char, TrieNode> _children = new Dictionary<char, TrieNode>();
public Dictionary<char, TrieNode> Children
{
get { return _children; }
}
view raw Children4.cs hosted with ❤ by GitHub

That was all it took to make me a happy camper ?.

a happy camper

▬ Takeaway ▬

Auto Property initialization creates a backing field while Expression Bodied property one does not.

The post Expression Bodied Collection Property Initialization Gotcha in C# appeared first on Slight Edge Coder.

Heroku

Build apps, not infrastructure.

Dealing with servers, hardware, and infrastructure can take up your valuable time. Discover the benefits of Heroku, the PaaS of choice for developers since 2007.

Visit Site

Top comments (0)

Billboard image

Create up to 10 Postgres Databases on Neon's free plan.

If you're starting a new project, Neon has got your databases covered. No credit cards. No trials. No getting in your way.

Try Neon for Free →

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay