Behind the Scenes Look at C#: Properties continued

We will continue our discussion covering C# properties. We will cover the MSIL code that the compiler generates when you define a C# property, read-only, write-only properties, and static properties. This article is the fourth in a series covering C#.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 15
July 20, 2005
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

MSIL Code and Properties

To discuss the generated MSIL code I will modify the worker example to a simpler version, so we can concentrate on one property and see what's going on with the MSIL code. Copy the following code and compile it, then load the application with the Ildasm.exe tool.

using System;
namespace property
{
class Class1
{
static void Main(string[] args)
{
Worker person = new Worker();
person.Name = "Michael";
Console.WriteLine(person.Name);
}
}

public class Worker
{
private string name;

public string Name
{
get
{
return name;
}

set
{
name = value;
}
}
}
}

Navigate to the worker class in the generated MSIL code.

It's clear that we have a property called Name, but why do we have two more methods (get_Name and set_Name)? Actually, the C# compiler generates a property along with its associated get_propertyName and set_propertyName methods, which read and write the value from/to the private field. You may ask yourself, why does the compiler generate a property while it has already been generated -- the get and set methods? Why do we need the property then?

Actually, the runtime doesn't know about the C# construction property. The runtime has a complete knowledge of methods, and as you will see shortly, the compiler determines when to call the method get_Name and the method set_Name each time you read and write with the property. We need the property construction for reflection; for now think of reflection as a way to get information about a loaded object in run time. Now, let's look at the Name property.

The Name Property

It's defined using the directive .property and marked as an instance member using the instance keyword, followed by the data type of the property and finally the name of the property. The get method is listed here using the .get directive. Note that the return data type is the same as the data type of the property. The set method is listed in the property using the .set directive. Note that it has only one parameter of type string. Now let's take a look at the methods MSIL code. Double click on the get_Name method.

Again, spending some time understanding the MSIL generated code crystallizes in your mind how the C# code gets executed. The get_Name method returns the value of the property (through the private field). The ldarg.0 instruction loads the first parameter, and as we said before, the get_Name method is a parameterless method.

What actually happens is that the MSIL code always refer to the this pointer as the first method's argument. So all the instance methods have the first argument (it's zero-based so it's number 0) refer to the this pointer. The ldfld instruction (stands for Load Field, as we have said before) loads the field of the object in hand. In other words, it loads the field of the object that we have a pointer to (the this pointer from the first step). As you can see it loads the field Worker::name.

The instruction stloc.0 stores the value of the name field into the first local variable, and the ldloc.0 instruction (stands for Load Location) loads the value back to the stack. The method returns with the value of the field. Let's take a look at the set_Name method.

The first issue I want to discuss is the Set_Name(string 'value'). As you know, 'value' is a keyword in C# so you can't just use it in your code as an identifier. The C# compiler always generates the set_xxx methods with one parameter named 'value,' and it has the same data type as the property. The get method returns the same data type as defined in the property too, so it's just one data type in both of the methods. In other words, there was no magic when you used an expression like this.name = value to assign the value of the value parameter to the private field name.

Okay, the ldarg.0 loads the this pointer on the stack, then the instruction ldarg.1 loads the argument number 2 (which is the 'value' parameter) on the stack. After that, the instruction stfld stores the value of the 'value' parameter to the field Worker::name, and then the method returns using the instruction ret. I think that now you have a better understanding of the generated MSIL code. Let's look at the Main method's MSIL code.

I think that now, understanding the Main method is not a big issue. The newobj instruction instantiates a new object (in our case an object of type worker). The stloc.0 stores the reference of the person object on the stack, then the ldloc.0 loads the reference. The ldstr "Michael" instruction loads the string Michael, then a call to the method set_Name(string) is put in place by using the instruction callvirt (call virtual method). Note that the constant value "Michael" is passed to the method (through the instructions) and that's why the value keyword in C# (which is the name of the paramter in MSIL) refers to the value itself (in our example "Michael").

Again, we load the location zero using the instruction ldloc.0, which contains the object reference person, and call the method get_Name(). Then we call the Console.WriteLine method and return to the caller using the instruction ret. Some of you may think that using a property to control the access to a field will slow down the application performance, but this is far from the truth. Actually the runtime JIT compiler knows how to optimize the code of the more method calls (the get and set methods which result in more lines of code to access the field), and believe it or not, it generates even faster code than the code that uses public fields.

I think many of you will want to go to the nearest bookshop and get a book about MSIL and the CLR. I advise you to master C# first, then get a book about MSIL. In fact, it's uncommon to write MSIL using the assembler, but there are some very scientific applications which need just that. Compiler designers who need to develop a compiler for their programming languages that target the .NET runtime will also find that they need to master MSIL code.

We have been discussing properties on instances, but we haven't discussed static properties, so let's do that.

Static Properties

Like static methods, static properties have defined on the class itself, not on an instance of the class. Sometimes you will find yourself in a situation where you have an attribute that has a class scope (a static field), which means that the field value is shared between all the instances of the class. For the same reasons that we have used properties with private fields, we will use a public static method with a private static field.

You access the property using the class identifier (not in the form of instance.property). A static property accesses only a static field. This makes sense because the get/set methods need the this pointer to access the field. A static property doesn't have a pointer to this because it has a class scope. So an instance property can access a static field because static data are exposed to static and instance methods. The following updated version of the Worker example illustrates the use of static properties.

using System;
namespace property
{
class Class1
{
static void Main(string[] args)
{
try
{
Worker.Department = "IT";
Worker w1 = new Worker();
w1.FirstName = "Michael";
w1.LastName = "Youssef";
Console.WriteLine(w1);

Console.WriteLine();

Worker w2 = new Worker();
w2.FirstName = "Maria";
w2.LastName = "Meleka";
Console.WriteLine(w2);
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}

public class Worker
{
private string firstName;
private string lastName;
private static string department;

public string FirstName
{
get
{
return this.firstName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.firstName = value;
}
}
}

public string LastName
{
get
{
return this.lastName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.lastName = value;
}
}
}

public static string Department
{
get
{
return department;
}

set
{
if(value != "IT")
{
throw new ArgumentException("All Workers must be in the IT Department");
}
else
{
Worker.department = "IT";
}
}
}

public override string ToString()
{
return firstName +" "+lastName+" is working in "+department;
}
}
}

The result that you will get in the console window is this:

We have declared the department private field as static, and the department property as static too. Note that by using a static property instead of a public static field we are able to do our data validation and throw exceptions, as we have done with the instance properties.

Read or Write Properties

 

All of the above examples of properties define read/write properties through the declaration of the get and the set accessors in the property declaration. You can declare a read-only property and a write-only property. Each of them is perfect in a specific scenario.

For example, you can use a read-only property when you need to define a property such that the client code can't change its value; the client code can only read (or get) the value. You declare a read-only property by omitting the set accessor part of the property -- thus it contains the logic that can gets the value only.

As I said before, it's very uncommon to declare a property as write-only but it does happen, and you may need it. For example, you have to store some very sensitive information (maybe a password) which can't be read by client code (but of course it will be read by the class members through the private field). To declare such a property you need to omit the get accessor part of the property.

The following version of the Worker example defines read-only and write-only properties. Note that you need to initialize the private field that the read-only property reads through the use of a construction called class constructor. The class constructor is simply a method that has the same name as the class, and is called when you create an instance of the class. It's a perfect place to put object initialization code. We will discuss the class constructor in detail in this series.

The Worker class has a read-only property that has only the get accessor defined, which is the FullName property. This property returns a string representation of the full name of the worker, and you can't change or assign a value to this property because it's read-only. Note that the FullName property returns the value of the private field firstName concatenated with the value of the private field lastName. In other words, the property doesn't to have its own private field that the property uses to store the data.

The Worker class contains a write-only property. It's the Password property. Although I don't like to define any write-only properties in my classes, I thought that you should know about it. Maybe one day you may find a scenario where you need to use this kind of property. 

Copy the following code and compile it:

using System;
namespace property
{
class Class1
{
static void Main(string[] args)
{
try
{
Worker.Department = "IT";
Worker w1 = new Worker();
w1.FirstName = "Michael";
w1.LastName = "Youssef";
Console.WriteLine(w1.FullName);
Console.WriteLine("Please Enter the Password");
w1.Password = Console.ReadLine();
Console.WriteLine("Your Password has been stored");
Console.ReadLine();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}
}

public class Worker
{
private string firstName;
private string lastName;
private static string department;
private string password;

public string FirstName
{
get
{
return this.firstName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.firstName = value;
}
}
}

public string LastName
{
get
{
return this.lastName;
}

set
{
if(value == String.Empty)
{
throw new ArgumentNullException();
}
else
{
this.lastName = value;
}
}
}

public static string Department
{
get
{
return department;
}

set
{
if(value != "IT")
{
throw new ArgumentException("All Workers must be in the IT Department");
}
else
{
Worker.department = "IT";
}
}
}

public string FullName
{
get
{
return this.firstName + " " + this.LastName;
}
}

public string Password
{
set
{
this.password = value;
}
}
}
}

Run the code and you will be prompted to enter your password; then it will be stored in the property.

Let's load the MSIL code to differentiate between read-only, write-only and read/write properties. Load the application with the Ildasm.exe tool and navigate to the Worker class, then expand it.

As you can see, because the FullName property is a read-only property, it has only the get_FullName method. The Password property has only the method set_Password because we have defined it as a write-only property. 

blog comments powered by Disqus
C# ARTICLES

- Beginning C#
- ASP.NET RedirectPermanent Method using C# an...
- C Programming Language and UNIX Pioneer Pass...
- Using Facebook JavaScript SDK in ASP.NET wit...
- ASP.NET Export to Excel and Word using VB.NE...
- WAV and MP3 Streaming with ASP.Net and C#
- Game Programming using SDL: the File I/O API
- C# and Java Developer Jobs on the Rise
- The Future Evolution of C# and VB.NET
- C# If and Else-if Statements
- How To Use the C# String Replace Method
- 5 Ways to Parse XML in C#
- C# Meets Design Patterns
- Coding a CRC-Generating Algorithm in C
- Cyclic Redundancy Check

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 11 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials