Click here to Skip to main content
15,895,746 members
Articles / Programming Languages / C# 6.0

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

Rate me:
Please Sign up or sign in to vote.
5.00/5 (6 votes)
16 Dec 2015CPOL1 min read 11K   2   2
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:

C#
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:

C#
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:

C#
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:

C#
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:

C#
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, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect Bill Wagner Software LLC
United States United States
Bill Wagner is one of the world's foremost C# developers and a member of the ECMA C# Standards Committee. He is President of the Humanitarian Toolbox, has been awarded Microsoft Regional Director and .NET MVP for 10+years, and was recently appointed to the .NET Foundation Advisory Council. Wagner currently works with companies ranging from start-ups to enterprises improving the software development process and growing their software development teams.

Comments and Discussions

 
SuggestionSmall correction. Pin
Member 1114611712-Jan-19 15:09
Member 1114611712-Jan-19 15:09 
Question=> Pin
Member 1202398818-Dec-15 18:42
Member 1202398818-Dec-15 18:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.