Summary: in this tutorial, you’ll about the C# property and how to use the properties effectively.
Introduction to the C# property
By definition, a property is a member of a class that provides a flexible way to read, write, or compute the value of a private field.
For example, the following defines the class Person
with three private fields firstName
, lastName
, and age
:
// Person.cs
class Person
{
private string firstName;
private string lastName;
private int age;
}
Code language: C# (cs)
To assign values to and read values from these private fields, you use properties. The following shows how to add three properties to the Person
class:
// Person.cs
class Person
{
private string firstName;
private string lastName;
private int age;
public string FirstName
{
get { return firstName; }
set { firstName = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
public int Age
{
get { return age; }
set { age = value; }
}
}
Code language: C# (cs)
In this example, we declare a property like a field with a get
and set
blocks. The get
and set
are called the property accessors.
When you read from a property, the get
accessor executes. And when you assign a value to a property, the set
accessor executes. For example:
// Program.cs
var p1 = new Person();
p1.FirstName = "John";
p1.LastName = "Doe";
Console.WriteLine($"{p1.FirstName} {p1.LastName}");
Code language: C# (cs)
In this example:
- First, create an instance of the
Person
class. - Second, assign the values to the
FirstName
andLastName
properties. - Third, read values from the
FirstName
andLastName
properties.
Using C# property for data validation
Since a property provides a central place to assign a value to a private field, you can validate the data and throw an exception if the data is not valid.
Suppose you want to implement the following validation rules:
- The first name and last name are not null or empty
- The age is between 1 and 150
To do that, you can add the validation logic to the set
accessors of the properties as shown in the following example:
// Person.cs
class Person
{
private string firstName;
private string lastName;
private int age;
public string FirstName
{
get
{
return firstName;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("The first name must not be empty or null");
}
firstName = value;
}
}
public string LastName
{
get
{
return lastName;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("The last name must not be empty or null");
}
lastName = value;
}
}
public int Age
{
get
{
return age;
}
set
{
if (value < 0 || value > 150)
{
throw new ArgumentException("The age must be between 1 and 150");
}
age = value;
}
}
}
Code language: C# (cs)
The following program causes an exception because the age is out of the valid range (1-150)
// Program.cs
var p1 = new Person();
p1.FirstName = "John";
p1.LastName = "Doe";
p1.Age = 200; // cause an exception
Code language: C# (cs)
Output:
Unhandled exception. System.ArgumentException: The age must be between 1 and 150
Code language: C# (cs)
C# computed property
To create a computed property, you can implement the get
accessor. For example, you can create a FullName
property that returns the concatenation of the first name and last name:
// Person.cs
class Person
{
private string firstName;
private string lastName;
private int age;
public string FirstName
{
get
{
return firstName;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("The first name must not be empty or null");
}
firstName = value;
}
}
public string LastName
{
get
{
return lastName;
}
set
{
if (string.IsNullOrEmpty(value))
{
throw new ArgumentException("The last name must not be empty or null");
}
lastName = value;
}
}
public int Age
{
get
{
return age;
}
set
{
if (value < 0 || value > 150)
{
throw new ArgumentException("The age must be between 1 and 150");
}
age = value;
}
}
public string FullName
{
get
{
return $"{FirstName} {LastName}";
}
}
}
Code language: C# (cs)
And you can read from the FullName
property:
// Program.cs
var p1 = new Person();
p1.FirstName = "Jane";
p1.LastName = "Doe";
p1.Age = 25;
Console.WriteLine(p1.FullName);
Code language: C# (cs)
Output:
Jane Doe
Code language: C# (cs)
If you attempt to assign a value to the FullName
property, you’ll get a compilation error. For example:
// Program.cs
var p1 = new Person();
p1.FirstName = "Jane";
p1.LastName = "Doe";
p1.Age = 25;
Console.WriteLine(p1.FullName);
p1.FullName = "Jane Smith";
Code language: C# (cs)
Error:
Property or indexer 'Person.FullName' cannot be assigned to -- it is read only
Code language: C# (cs)
C# auto-implemented properties
If you have a property that requires no additional logic in the set
or get
accessors, you can use an auto-implemented property.
The following example defines the Skill
class that has two private fields name
and rating
, and the corresponding properties:
class Skill
{
private string name;
private sbyte rating;
public string Name
{
get { return name; }
set { name = value; }
}
public sbyte Rating
{
get { return rating; }
set { rating = value; }
}
}
Code language: C# (cs)
Since the accessors of the properties have no additional logic besides reading from and writing to private fields, you can use auto-implemented properties like this:
class Skill
{
public string Name { get; set; }
public sbyte Rating { get; set; }
}
Code language: C# (cs)
When the C# compiler encounters an auto-implemented property, it creates a private, anonymous field that can be accessed through the set
and get
accessors.
As you can see, the auto-implemented properties make the code more concise in this case.
In C# 9 or later, you can init an auto-implemented property like this:
class Skill
{
public string Name { get; set; }
public sbyte Rating { get; set; } = 1;
}
Code language: C# (cs)
In this example, we initialize the Rating
property so that its value is one when you create a new instance of the Skill class.
Summary
- A property is a member of a class that provides a flexible way to read, write, or compute the value of a private field.
- A property contains get and/or set accessors.
- The get accessor executes when you read the value from the property while the set accessor executes when you assign a value to the property.
- Use auto-implemented property if the get and set accessors have no additional logic to make the code more concise.