To declare a property in C#, we have to declare access methods (for reading and changing) of the respective property and to decide how we will store the information related to the property in the class.
Before we declare the methods, however, we have to declare the property of the class. Formal declaration of properties appears in the following way:
[<modifiers>] <property_type> <property_name>
With
<modifiers>
we have denoted both the access modifiers and other modifiers (e.g.static
, to be discussed in the next section of this chapter).They are not a mandatory part of the declaration of a field.
The type of the property
<property_type>
specifies the type of the values of the property. It may be either a primitive type (e.g.int
), or a reference type (e.g. array).Respectively,
<property_name>
is the name of the property. It must begin with a capital letter and to satisfy thePascalCase
rule, i.e. every new word that is adjoined to the end part of the property name, starts with a capital letter. Here are some examples of properly named properties:// MyValue property
public int MyValue { get; set; } // Color property
public string Color { get; set; } // X-coordinate property
public double X { get; set; }
The Body of a Property
Like classes and methods in C# properties also have bodies, where the methods for access are declared (accessors).
[<modifiers>] <property_type> <property_name>
{
// … Property's accessors methods go here}
The body of a property begins with an opening bracket "
{
" and ends with a closing bracket – "}
". Properties should always have a body.Method for Reading the Value of a Property (Getter)
As we explained, the declaration of a method for reading a value of a property (in the literature called a getter) is made in the body of a property by using the following syntaxes:
get { <accessor_body> }
The content of the block surrounded by the braces (
<accessor_body>
) is similar to the contents of any method. The actions, which should be performed to return the result of the method, are declared in it.The method of reading the value of a property must end with a
return
orthrow
operation. The type of the value, which is returned as a result of this method, has to be the same as<property_type>
described in the property declaration.Although earlier in this section we considered many examples of declared properties with a method for reading their values, let’s consider another example of a property –
Age
, which is of typeint
and is declared via a field in the same class:private int age; // Field declaration public int Age // Property declaration {
get { return this.age; } // Getter declaration }
Calling a Method for Reading Property’s Value
Assume that the property
Age
from the last example is declared in the classDog
. Then calling the method for reading the value of the property is done by a “dot” notation, applied to a variable of the type, in the class of which the property is declared:Dog dogInstance = new Dog();
// …
int dogAge = dogInstance.Age; // Getter invocation Console.WriteLine(dogInstance.Age); // Getter invocation
The last two lines of the example show that when accessing through a dot notation the name of the property, its getter method (method for reading its value) is called automatically.
Method for Modifying Property’s Value (Setter)
Like the method of reading the property’s value we can also declare the method of changing (modifying) the value of a property (in the literature known as setter). It is declared in the body of a property with
void
return value and the assigned value is accessible through an implicit parametervalue
.The declaration is made in the body of the property through the following syntax:
set { <accessor_body> }
The contents of the block surrounded by arrow brackets –
<accessor_body>
are similar to the content of any method. It declares the actions that must be performed to change the value of the property. The method uses a hidden parameter called
value
, which is available in C# by default and contains the new value of the property. The type of the parameter is the same as the type of the property.Let’s add the example for the property
Age
in the classDog
to illustrate what we discussed so far:private int age; // Field declaration
public int Age // Property declaration {
get { return this.age; }
set { this.age = value; } // Setter declaration }
Calling a Method for Modifying the Property’s Value
Calling the method to modify the property’s value is performed via the “dot”
notation, applied to the variable of the type, in the class of which the property is declared:
Dog dogInstance = new Dog();
//
…dogInstance.Age = 3; // Setter invocation
In the last line where the value 3 is assigned the setter method of the property
Age
is called. In this way the value is saved in the parametervalue
and is assigned to the setter method of the propertyAge
. In our example, the value of the variablevalue
is assigned to the fieldage
from the classDog
, but in the general case this can be handled in a more complicated way.Assertion of the Input Values
It is a good practice in the programming process to check the validity of the input values for the setter method of modifying a property and if they are not valid to take the necessary “measures”. Mostly, in case of incorrect input data an exception is caused.
Consider again the example with the age of the dog. As we know the age has to be a positive number. To prevent someone from assigning a negative number or a zero to the property
Age
, we add the following validation at the beginning of the setter method:public int Age {
get { return this.age; } set
{
// Take precaution: perform check for correctness if (value < 0)
{
throw new ArgumentException(
"Invalid argument: Age should be a positive number.");
}
// Assign the new correct value
this.age = value;
} }
In case someone tries to assign a value to
Age
, which is a negative number or 0, the code will throw an exception from the typeArgumentException
, with details of the problem.To protect itself from invalid data a class must verify the input values for all properties and constructors submitted to the setter methods, as well as all methods, which can change a field of a class. This programming practice to protect classes from invalid data and invalid internal states is widely used and is a part of the "Defensive Programming" concept, which we will discuss in chapter "High-Quality Programming Code".