Properties
Learn to control access to class fields using properties.
We'll cover the following...
In C#, there are regular and special methods that control access to class fields. These methods are called properties.
Define a property
Properties are created with the following syntax:
// Like other members, properties can have acess modifiers
[access modifiers] property_type property_name
{
get
{
// Get block contains actions to perform when returning the value of the field
}
set
{
// Set block contains actions to perform when setting the value of the field
}
}
Properties don’t hold any value. They only act as intermediaries between the external code and the fields.
Let’s look at an example.
Here, the Car class defines the private model and price fields that store the model and the price of the car. Along with these fields, there are two public properties called Model and Price.
Property usage
Let’s take the model field, for example. With the help of the Model property, we can control the access to that field:
get { return model; } // Returns the value of the field
The get block returns the value of the field. Depending on the requirements, it can perform checks or other manipulations before returning the data.
set { model = value; } // Sets the value of the field
We set the value of the model field in the set block. The value is a placeholder for the value that’s passed to the property:
car.Model = "Lexus LS 460L"; // value
We can work with properties just like with regular fields. When we assign a value to a property, the set block is triggered. When we read the value of a property, the get block is triggered.
What’s the use of properties if they only pass values back and forth?
Validate values with properties
Properties have the capacity to control the access. In our example, the price field shouldn’t have a negative value, because price can’t be negative. We can prevent users from setting a negative value with the help of a property:
private decimal price;
public decimal Price
{
get { return price; }
set
{
if (price < 0)
{
price = 0;
}
else
{
price = value;
}
}
}
Now, if the user sets a negative number to the Price property, price will be zero and therefore won’t be negative.
Access modifiers
We can control access to a property using access modifiers. We can decorate the whole property or its separate blocks:
public string Model
{
get { return model; }
private set { model = value; }
}
In the example above, the property itself is public. We can apply more restrictive modifiers to individual blocks.
Making the set block private makes it impossible for an external class to set the value of the property.
When setting access modifiers to set and get blocks, we must consider the following constraints:
-
We can’t set an access modifier explicitly if the property contains only one block (
setorget):public string Name { private get; // Invalid, must also have the set block } -
Only one block can have an access modifier at a time:
public string Name { private get; private set; // Invalid, only one block can have an access modifier } -
The access modifier of the
setorgetblock must be more restrictive than the modifier attached to the property.internal string Name { public get; // Cannot be public, because the property is internal set; }
Auto-implemented properties
When we have many fields and don’t require complex access-control logic, we can use auto-implemented properties.
Consider the following example:
using System;
namespace Properties
{
public class Car
{
private string model;
public string Model
{
get { return model; }
set { model = value; }
}
private decimal price;
public decimal Price
{
get { return price; }
set { price = value; }
}
private int year;
public int Year
{
get { return year; }
set { year = value; }
}
}
}
Imagine that we have 20 more fields and we have to write 20 more properties that only pass the respective field value back and forth. That will quickly get tedious.
Auto-implemented properties were introduced to .NET to avoid this:
public string Model { get; set; }
This auto-property has a backing field that’s automatically generated by the compiler during compilation:
[CompilerGenerated]
private string <Model>k__BackingField;
public string Model
{
[CompilerGenerated]
get
{
return <Model>k__BackingField;
}
[CompilerGenerated]
set
{
<Model>k__BackingField = value;
}
}
The compiler also generates the respective get and set blocks.
The primary advantage of auto-properties is that they can be expanded at any moment if any additional logic is needed.
Access modifiers can be used in the same way as with regular properties:
public string Model { get; private set; }
If we make all properties auto-implemented, this would be our resulting Car class:
Extra
.NET IDEs contain shortcuts because creating a property for a field is among the most common operations performed by software developers. For instance, in Visual Studio, we can automatically generate a property for a field by using the refactoring functionality: