C# Parameterless Properties – (Part 1)

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:

  1. // Example 1
  2. public int Age
  3. {
  4.   get { return this.age; }
  5.   set { this.age = value; }
  6. }

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 “()”.

  1. // Example 2
  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.

  1. // Listing 1
  2. class PropertiesClass
  3. {
  4.     #region Fields
  5.     private int age; // a private field of type integer to hold the age value.
  6.     #endregion
  7.  
  8.     #region Properties
  9.     /// <summary>
  10.     /// Property Age is used to get or to set the value of the private field age.
  11.     /// </summary>
  12.     public int Age
  13.     {
  14.         get { return this.age; }    // getter function
  15.         set { this.age = value; }   // setter function
  16.     }
  17.     #endregion
  18.  
  19.     #region Constructor
  20.     /// <summary>
  21.     /// The constructor.  At class instantiation we will set the value to zero.
  22.     /// </summary>
  23.     public PropertiesClass()
  24.     {
  25.         this.age = 0;
  26.     }
  27.     #endregion
  28. }

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.

Figure 1: IL DASM screenshot

Figure 1: IL DASM screenshot


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:

  1. //Listing 2
  2. .property instance int32 Age()
  3. {
  4.   .get instance int32 PropertiesExample.PropertiesClass::get_Age()
  5.   .set instance void PropertiesExample.PropertiesClass::set_Age(int32)
  6. } // 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.

  1. //Listing 3
  2. .method public hidebysig specialname instance int32 
  3.         get_Age() cil managed
  4. {
  5.   // Code size       12 (0xc)
  6.   .maxstack  1
  7.   .locals init ([0] int32 CS$1$0000)
  8.   nop
  9.   ldarg.0
  10.   ldfld      int32 PropertiesExample.PropertiesClass::age
  11.   stloc.0
  12.   br.s       IL_000a
  13.   ldloc.0
  14.   ret
  15. } // 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.

  1. //Listing 4
  2. /// <summary>
  3. /// Property Age is used to get or to set the value of the private field age.
  4. /// </summary>
  5. public int Age
  6. {
  7.   get { return this.age; }    // getter function
  8.   private set { this.age = value; }   // setter function <- private
  9. }

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).

  1. //Listing 5
  2. .method public hidebysig specialname instance void 
  3.         set_Age(int32 'value') cil managed
  4. {
  5.   // Code size       9 (0x9)
  6.   .maxstack  8
  7.   nop
  8.   ldarg.0
  9.   ldarg.1
  10.   stfld      int32 PropertiesExample.PropertiesClass::age
  11.   ret
  12. } // 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.

  1. //Listing 6
  2. // NOTE: method names in C# should start in upper case but here we 
  3. // are using lower case in order to match it with the generated IL code.
  4. public void set_Age(int value) 
  5. {
  6.   this.age = value;
  7. }

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