In this blog entry we will take a look at C# Properties. Properties in C# are used as fields. Their main purpose is to isolate the actual data by allowing the developer to perform some validation prior the client access the guarded member variable. Properties are meant to be simple and efficient. In Object Oriented terms, Properties are known as getters and setters. C# provides an easy syntax to define a Property. A simple example is shown below:
// Example 1
public int Age
{
get { return this.age; }
set { this.age = value; }
}
Properties come in two flavours, parameterless and parameterful. The example above, Example 1, shows the definition and implementation of a parameterless Property. Paremeterless Properties, as their name suggests do not take any parameter when they are accessed. Example 2 shows how the Property defined in Example 1 can be accessed. Note the difference from calling a method. Properties are not followed by parenthesis “()”.
// Example 2
Console.WriteLine("Age: {0}", propertiesExample.Age);
But before we go into the use of Properties we shall see how the Common Language Runtime (.NET Framework CLR) transforms them and see from where the ‘value’ variable in Example 1 comes into the picture.
C# Code
We will use a very simple C# class in order to demonstrate how Properties are transformed in IL. The sample code is given in Listing 1. The comments explain the important lines of code in this example.
// Listing 1
class PropertiesClass
{
#region Fields
private int age; // a private field of type integer to hold the age value.
#endregion
#region Properties
/// <summary>
/// Property Age is used to get or to set the value of the private field age.
/// </summary>
public int Age
{
get { return this.age; } // getter function
set { this.age = value; } // setter function
}
#endregion
#region Constructor
/// <summary>
/// The constructor. At class instantiation we will set the value to zero.
/// </summary>
public PropertiesClass()
{
this.age = 0;
}
#endregion
}
On class instantiation we are initialising the private variable age to zero. Any class using the PropertiesClass class can read or change the value of the private field age using the Property Age.
The transformation
When the C# compiler compiles Properties, the IL emits two methods – one for setting the value (setter) and another to get the value (getter). The IL elements of the code in Listing 1 are shown in Figure 1.
Note that the methods get_Age() and set_Age() are not present in our original code (Listing 1). If we expand the Property Age in IL DASM we will see how the compiler transformed our Property:
//Listing 2
.property instance int32 Age()
{
.get instance int32 PropertiesExample.PropertiesClass::get_Age()
.set instance void PropertiesExample.PropertiesClass::set_Age(int32)
} // end of property PropertiesClass::Age
In Listing 2 we see that whenever the get part of the Age Property is called, the get_Age() method is called. Similarly, it can be said to the set section of our Property. Now let’s examine the code within the get_Age() and set_Age() methods. These two are the actual getter and setter methods doing the job.
The get accessor
The IL code created in the getter method, get_Age(), is shown in Listing 3.
//Listing 3
.method public hidebysig specialname instance int32
get_Age() cil managed
{
// Code size 12 (0xc)
.maxstack 1
.locals init ([0] int32 CS$1$0000)
nop
ldarg.0
ldfld int32 PropertiesExample.PropertiesClass::age
stloc.0
br.s IL_000a
ldloc.0
ret
} // end of method PropertiesClass::get_Age
The first thing that we observe is that the getter method has the same accessibility of the property, that is, public. This accessibility behaviour can be overridden by specifying the accessibility level you want. The example below shows how to make the getter method public and the setter method private. The .NET Framework supports any combination given that the Property’s accessibility is more visible than the methods. That is, one cannot have a private Property and make the setter public. This is because the end developer calls the setter method through the Property rather than call it directly. So the Property must be accessible from outside the class.
//Listing 4
/// <summary>
/// Property Age is used to get or to set the value of the private field age.
/// </summary>
public int Age
{
get { return this.age; } // getter function
private set { this.age = value; } // setter function <- private
}
The rest of the IL code in Listing 3 is to read the value of the class member variable age and return it.
The set accessor
Now, let’s take a look at the IL code generated by the setter accessor (Listing 5).
//Listing 5
.method public hidebysig specialname instance void
set_Age(int32 'value') cil managed
{
// Code size 9 (0x9)
.maxstack 8
nop
ldarg.0
ldarg.1
stfld int32 PropertiesExample.PropertiesClass::age
ret
} // end of method PropertiesClass::set_Age
We notice again the public accessibility emitted by IL for this method. Of particular importance here, is the variable parameter value. This parameter is not in our original code but is emitted by IL. This parameter is the variable we used in our C# code. The variable value is an implicit parameter which is part of the C# standard. In a more simplistic view, the set accessor method can be re-written in C# as shown in Listing 6.
//Listing 6
// NOTE: method names in C# should start in upper case but here we
// are using lower case in order to match it with the generated IL code.
public void set_Age(int value)
{
this.age = value;
}
Conclusion
This week we saw what properties are and how these are transformed at IL level. Next time, we will take a look at an example to see the benefits of using Properties.
Articles
- C# Parameterless Properties – (Part 1)
- C# Parameterless Properties – (Part 2)