Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

A C# 6 Gotcha: Initialization vs. Expression Bodied Members

0.00/5 (No votes)
17 Dec 2015 1  
A C# 6 gotcha: Initialization vs. Expression Bodied Members

I was asked to review a bit of code for a friend the other day, and the result may be illustrative for others. I’ve stripped out much of the code to simplify the question. Examine the following small program:

public class SomeContainer
{
    public IList<int> SomeNumbers => new List<int>();
}
class Program
{
    static void Main(string[] args)
    {
        var container = new SomeContainer();
        var range = Enumerable.Range(0, 10);
        foreach (var item in range)
            container.SomeNumbers.Add(item);
 
        Console.WriteLine(container.SomeNumbers.Count);
    }
}

If you run this sample, you’ll find that container.SomeNumbers has 0 elements.

How is that possible? Why does the container not have 10 elements?

The problem is this line of code:

public IList<int> SomeNumbers => new List<int>();

The author had used an expression bodied member when he meant to use an initializer for auto-property.

An expression bodied member evaluates the expression whenever the public member is accessed. That means that every time the SomeNumbers property of the container gets accessed, a new List<int> is allocated, and assigned to the hidden backing field for the SomeNumbers property. It’s as though the author wrote this:

public IList<int> SomeNumbers { get { return new List<int>(); } }

When you see it using the familiar syntax, the problem is obvious.

This fix is also obvious. Use the syntax for an initializer:

public IList<int> SomeNumbers { get; } = new List<int>();

Notice the changes from the original code. SomeNumbers is now a read only auto property. It also has an initializer. This would be the equivalent of writing:

public IList<int> SomeNumbers { get { return storage; } }

private readonly List<int> storage = new List<int>();

That expresses the design perfectly.

This just illustrates that as we get new vocabulary in our languages, we need to fully understand the semantics of the new features. We need to make sure that we correctly express our designs using the new vocabulary.

It’s really easy to spot when you make a mistake like this: every time you look at this property in the debugger, you’ll see that it re-initializes the property. That’s the clue that you’ve made this mistake.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here