Geeks With Blogs

News
Joe Mayo

Today, Somasegar announced that Visual Studio 2015 will be released on July 20th, 2015. This release will also include C# 6.0. This is the first in a series of posts on the new features of C# 6.0 and I’ll cover Auto-Property Initializers. This post discusses what an Auto-Property Initializer is, how to use it, and why it can help you write code more efficiently.

What is an Auto-Property Initializer?

An auto-property initializer allows you to set the value of a property at the same time you declare it in a class. Prior to C# 6.0, you need to set the property value in a constructor. This is normally not a problem because in the simple case, you set the value in a constructor, like this, and move on:

    public class PepperoniPizza
    {
        public decimal ExtraPrice { get; set; }

        public PepperoniPizza()
        {
            ExtraPrice = 0.25m;
        }
    }

This PepperoniPizza class has an ExtraPrice property, which is initialized in the constructor. That’s fine, but a couple considerations might be that 1) you need to explicitly declare a constructor just to initialize the value, 2) alternatively, you could have created a fully-implemented property and initialized the backing store field, 3) what if you have multiple properties, and/or 4) what if you have multiple constructors causing you to duplicate the initialization. In each case, you’re doing more work as well as separating initialization from declaration. Auto-property initializers let you do the opposite and combine declaration with initialization, like this:

    public class PepperoniPizza
    {
        public decimal ExtraPrice { get; set; } = 0.25m;
    }

With auto-property initializers, declare the auto-property as normal, but also use an assignment operator, specifying the value to initialize the property with. Then end the statement with a semi-colon. While you might not see this as a huge addition to the language, combined with several other features, this supports the C# 6.0 theme of having a set of features that simplify and make coding faster.

Accessors With Different Visibility

You can initialize auto-properties that have different visibility on accessors. Here’s an example with a protected setter:

        public string Name { get; protected set; } = "Cheeze";

The accessor can also be internal, internal protected, or private. The getter can also have different visibility and you will still be able to initialize the auto-property.

Read-Only Properties

In addition to flexibility with visibility, you can also initialize read-only auto-properties. Here’s an example:

        public List<string> Ingredients { get; } = 
            new List<string> { "dough", "sauce", "cheese" };

This example also shows how to initialize a property with a complex type. Also, auto-properties can’t be write-only, so that also precludes write-only initialization.

Initialization Expressions

Although the previous example initialized with a new List<string> instance, the value is still a static reference. Here are a couple more examples of expressions you can initialize auto-properties with:

        public decimal Price2 { get; set; } = 1m + 2m;

        public double Price3 { get; set; } = Math.PI;

The Price2 initializer is an addition expression, but the values are still numeric literals. Along the same lines, Math.PI is a constant initializer for Price3.

Non-Static Initializers are Verboten!

All of the initializers you’ve seen so far evaluate to a static expression. Non-static expressions, like the ones below, will generate compiler errors:

        // compiler errors
        //public string Name2 { get; set; } = Name;
        //public decimal Price4 { get; set; } = InitMe();

        decimal InitMe() { return 5m; }

The code tries to initialize Name2 with the value of Name, another property, which won’t work. Similarly, InitMe() is an instance method that won’t compile when used as the initializer for Price4. It doesn’t matter that InitMe() returns a numeric literal. Both of these situations generate a compiler error. Here's the error message for Price4:

    A field initializer cannot reference the non-static field, method, or property 'PizzaBase.InitMe()'

Virtual Properties and Type Initialization

A virtual auto-property can be initialized too. Here’s an example:

        public virtual decimal Price { get; set; } = 3.00m;

During initialization of the containing type, Price initializes before the constructor executes. It initializes like a field, meaning that a Price property override isn’t called during auto-property initialization. If you wanted the polymorphic initialization, you should initialize Price in the base class constructor, like this:

    public abstract class PizzaBase
    {
        public string Name { get; protected set; } = "Cheeze";

        public virtual decimal Price { get; set; } = 3.00m;

        public PizzaBase(IEnumerable extraIngredients)
        {
            Price = 2.95m;
        }
    }

The abstract PizzaBase class is a base class for the PepperoniPizza class shown below. This class overrides the Price property:

    public class PepperoniPizza : PizzaBase
    {
        public decimal ExtraPrice { get; set; } = 0.25m;

        decimal price;
        public override decimal Price
        {
            get
            {
                return price;
            }

            set
            {
                price = value + .50m;
            }
        }

        public PepperoniPizza(decimal extraFees) : base(new List { "pepperoni" })
        {
            ExtraPrice += extraFees;
            Name = "Pepperoni";
        }
    }

This is a scenario that’s more elegant to demo live, but you can test this by adding a full Price property override in a derived class (as shown in PepperoniPizza above), setting the setter breakpoint, and stepping through the code with the base class auto-property initializer. The base class Price auto-property initializer executes, but doesn’t call the full Price property setter in the derived class. Next, add a statement to the base class constructor to set Price to any value (as shown in PizzaBase above), step through the code, and observe that the assignment in the base class constructor does call the derived class full Price property when executed.

Summary

You’ve now been introduced to auto-property initializers. At the simplest level, but assign a value to an auto property where it’s declared. You learned that you can initialize read-only properties and the values must evaluate to a static expression. Non-static initializers cause compiler errors. This post also explained how auto-properties initialize like fields, but you can get polymorphism by initializing the auto-property in a constructor instead. Auto-property initializers, as one of a set of new features, are a new tool to help you write simpler code and save a few extra keystrokes.

@JoeMayo

Posted on Tuesday, June 30, 2015 12:24 AM | Back to top

Copyright © Joe Mayo | Powered by: GeeksWithBlogs.net