Difference between (auto) properties initializatio

2020-03-14 01:56发布

问题:

What is the difference between the following expressions for initializing the properties in C# 6:

1. Auto-Property initialized from constructor

public class Context1
{
    public Context1()
    {
        this.Items = new List<string>();
    }

    public List<string> Items { get; private set; }
}

2: Property initialized from a backing field

public class Context2
{
    private readonly List<string> items;

    public Context2()
    {
        this.items = new List<string>();
    }

    public List<string> Items
    {
        get
        {
            return this.items;
        }
    }
}

3: Auto-Property new syntax in C# 6

public class Context3
{
    public List<string> Items { get; } = new List<string>();
}

4: Auto-Property new syntax in C# 6

public class Context4
{
    public List<string> Items => new List<string>();
}

回答1:

Listing 3 is C# 6's equivalent of listing 2, where the backing field is provided under the hood.

Listing 4:

public List<string> Items => new List<string>();

is equivalent to:

public List<string> Items { get { return new List<string>(); } }

which as you can imagine returns a new empty list every time you access the property.

The difference between listings 2/3 and 4 is further explored in this Q&A with an example.

Listing 1 is just an auto property with a getter and a private setter. It's not a readonly property in that you can set it anywhere you can access any of the type's private members. A readonly property (that is, a getter-only property) can only be initialized either in a constructor or in the property declaration, much like a readonly field.



回答2:

Auto-property is a short designation for auto-implemented property, where the developer doesn't need to explicitly declare the backing field and the compiler sets one up behind the scenes.

1. Auto-Property with private setter

public class Context1
{
    public Context1()
    {
        this.Items = new List<string>();
    }

    public List<string> Items { get; private set; }
}

Auto-properties can have different accessibilities for setter and getter by specifying a more restrictive accessibility for the accessor for which the accessibility differs from the property's accessibility.

Other examples are:

public string Prop1 { get; private set; }
public string Prop2 { get; protected set; }
public string Prop3 { get; internal set; }
public string Prop4 { protected internal get; set; }

These accessors with different accessibility can be accessed for anywhere the that accessibility determines, not just from the constructor.

2. Read-only property with backing field

public class Context2 { private readonly List items;

public Context2()
{
    this.items = new List<string>();
}

public List<string> Items
{
    get { return this.items; }
}

} Prior to C#6, the only way to set the value of a read-only property was to explicitly declare the backing field and set it directly.

Because the field has the readonly accessor, it can only be set during the construction of the object.

3. Read-Only Auto-Property

public class Context3
{
    public List<string> Items { get; } = new List<string>();
}

Starting with C#6, §2 can be handled by the compiler by have an backing field generated like for read-write auto-properties but, in this case, the backing field is read-only and can only be set during the construction of the object.

4. Read-only Auto-Property with expression bodied getter

public class Context4
{
    public List<string> Items => new List<string>();
}

When properties have a value that changes every time it is get, C#6 allows to declare the body of the getter using a lambda-like syntax.

The above code is equivalent to this:

public class Context4
{
    public List<string> Items
    {
        get { return new List<string>(); }
    }
}